三、引用
1. 什么是引用
引用,顾名思义是某一个变量或对象的别名,对引用的操作与对其所绑定的变量或对象的操作完全等价。引用在使用时,有几个要注意的地方:
- &不是求地址运算符,而是起到标志作用
- 引用的类型和绑定的变量类型必须相同 (指针也一样)
- 声明引用的同时,必须对其进行初始化,否则报错。
- 引用相当于变量或者某个对象的别名,但是不能再将已有的引用名作为其他变量或者对象的名字或别名 (和指针不一样。)
- 引用不是定义一个新的变量或对象,因此内存不会为引用开辟新的空间存储这个引用
- 不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | #include<iostream>
using namespace std;
int main(){
//语法:类型 &引用名=目标变量名;
int a = 3 ;
int &b = a ;
//此时a也会变成33
b = 33;
vector<string> names {"张三" , "李四" ,"王五"};
// 这仅仅是改变了str的值,并不会改变vector里面的元素
for(auto str:names){
str = "赵六";
}
//此处不会产生新的变量,所以修改的都是vector里面的元素
for(auto &str : names){
str = "赵六" ;
}
return 0 ;
}
|
2. 左值和右值
C++的表达式要么是左值 lvalue
,要么是右值 rvalue
这两个名词是从C语言继承过来的。左值可以出现在赋值语句的左侧和右侧,右值只能出现在右侧。最长见到左值和右值的地方,是在函数的参数以及报错的日志信息里面。
不能简单的以等号的左右来判断是否是左值还是右值
判断是否是左值,有一个简单的办法,就是看看能否取它的地址,能取地址的就是左值 。使用排除法,其他的即为右值。
左值可看作是 对象,右值可看作是 值 而有时候对象也可以是左值也可以右值,一句话概括:当一个对象成为右值时,使用的是它的值(内容) , 而成为左值时,使用的是它的身份(在内存中的位置)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | //只能把左值赋值给引用,不能把右值赋给引用
int square(int &n){
return n * n ;
}
int main(){
int x = 1000; // x是一个左值, 而 1000 是一个右值。
x = 1000 + 20 ; //x 是左值, 1000 + 20 是右值,
int b = 10; // b 是一个左值, 10 是一个右值
b = x ; //b是一个左值, 而 x依然是一个左值。
int num = 10 ;
square(num) ; //正确
square(5) //错误。因为5是右值 ,不能赋值引用。
return 0;
}
|
3. 左值引用
平常所说的引用,实际上指的就是左值引用 lvalue reference
, 常用单个 &
来表示。 左值引用只能接收左值,不能接收右值。const 关键字会让左值引用变得不同,它可以接收右值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | #include <iostream>
using namespace std;
//函数原型
int add(int &num1);
void print(vector<int> &scores);
int main(){
int a = 3 ;
int &b = a ; //ar是一个左引用,实际上可以看成是a的一个别名。
// 这是不允许的。
// 1. 从引用层面理解的话是: 引用接收的一个变量,给某个变量起别名
// 2. 从左右值的层面理解是,这是一个左值引用,只能接收左值。 3 属于右值。
int &c = 3 ; //错误!
int a = 3 ;
add(a) ; //正确
add(3) ; //错误! 参数要求的是一个左值引用,只能赋值左值 ,3 属于右值
vector<int> scores{60,70,80,90};
print(scores); //正确
print({60,70,80,90}); //错误!
}
|
4. 右值引用
为了支持移动操作,在c++11版本,增加了右值引用。右值引用一般用于绑定到一个即将销毁的对象,所以右值引用又通常出现在移动构造函数中。
看完下面的例子,左值和右值基本就清楚了,左值具有持久的状态,有独立的内存空间,右值要么是字面常量,要么就是表达式求值过程中创建的临时对象
1
2
3
4
5
6
7
8
9
10
11
12
13 | int main(){
int i = 66;
int &r = i ; //r 是一个左引用,绑定左值 i
int &&rr = i ; //rr是一个右引用,绑定到左值i , 错误!
int &r2 = i*42 ; // r2 是一个左引用, 而i*42是一个表达式,计算出来的结果是一个右值。 错误!
const int &r3 = i*42; // 可以将const的引用,绑定到右值 正确
int &&rr2 = i*42 ; // 右引用,绑定右值 正确
return 0 ;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | #include<vector>
using namespace std;
//函数原型
int add(int &&num1);
void print(vector<int> &&scores);
int main(){
int a = 3 ;
add(a) ; //错误!参数要求的是一个右值引用,只能赋值右值
add(3) ; //正确!
vector<int> scores{60,70,80,90};
//print接收的是一个右值,此处的scores是一个左值。
print(scores); //错误!
//{60,70,80,90} 属于右值。
print({60,70,80,90}); //正确
return 0 ;
}
|