文章目录
- 1.左值引用
- 2.常引用
- 2.1 const引用可以指向临时数据
- 2.2 const引用可以指向不同类型的数据
- 2.3 const引用作为函数参数
- 3.右值引用
- 4.std::move()函数
1.左值引用
左值引用只能绑定到左值上,不能绑定到右值上。
左值引用不能绑定到临时变量上,因为临时变量被系统当作右值。
所有变量都是左值,因为它们是有地址的。
任何函数里边的形参都是左值。
#include <iostream>
using namespace std;
int main()
{
int& ref1 = 20; // 错误,左值引用不能绑定到右值上
int a = 10, b = 20;
int& ref2 = a; // 正确,左值引用能绑定到左值上
int& ref3 = a + b; // 错误,左值引用不能绑定到右值上
return 0;
}
返回左值引用的函数、赋值运算符、下标运算符、解引用运算符、前置递增运算符、前置递减运算符等,返回的都是左值,可以将左值引用绑定到这类表达式的结果上。
#include <iostream>
using namespace std;
int main()
{
int i = 10;
int& ref = ++i; // 左值引用可以绑定到左值上,ref就变成了i的别名
i += 5;
cout << i << endl; // 16
cout << ref << endl; // 16
return 0;
}
2.常引用
引用可以被 const 修饰,这样就无法通过引用修改数据了,称为常引用。const
必须写在 &
符号的左边,才能算是常引用。
引用 int &p
相当于 int* const p
,常引用 const int &p
相当于 const int* const p
。
#include <iostream>
using namespace std;
int main() {
int height = 20;
int age = 10;
// p1不能修改指向,但是可以利用p1间接修改所指向的变量
int* const p1 = &age;
//p1 = &height; // 报错
*p1 = 30;
cout << age << endl; // 30
// ref1不能修改指向,但是可以通过ref1间接修改所指向的变量
int & const ref1 = age;
ref1 = 40;
cout << age << endl; // 40
// p2可以修改指向,但是不可以利用p2间接修改所指向的变量
int const* p2 = &age;
p2 = &height;
//*p2 = 30; // 报错
// ref2不能修改指向,也不可以通过ref2间接修改所指向的变量
int const &ref2 = age; // 常引用
//ref2 = 40; // 报错
return 0;
}
2.1 const引用可以指向临时数据
举例1:const引用指向常量
#include <iostream>
using namespace std;
int main() {
const int &ref = 30;
return 0;
}
举例2:const引用指向表达式
#include <iostream>
using namespace std;
int main() {
int a = 1;
int b = 2;
const int &ref = a + b;
return 0;
}
举例3:const引用指向函数返回值
#include <iostream>
using namespace std;
int func() {
return 8;
}
int main() {
const int &ref = func();
return 0;
}
2.2 const引用可以指向不同类型的数据
#include <iostream>
using namespace std;
int main() {
int age = 10;
const double &ref = age;
return 0;
}
当常引用指向了不同类型的数据时,会产生临时变量,即引用指向的并不是初始化时的那个变量。
举例1:查看常引用指向相同类型数据的汇编代码
#include <iostream>
using namespace std;
int main() {
int age = 10;
const int &ref = age;
age = 30;
cout << age << endl; // 30
cout << ref << endl; // 30
return 0;
}
举例2:查看常引用指向不同类型数据的汇编代码
#include <iostream>
using namespace std;
int main() {
int age = 10;
const long &ref = age;
age = 30;
cout << age << endl; // 30
cout << ref << endl; // 10
return 0;
}
2.3 const引用作为函数参数
const引用作为函数参数时,可以接受const和非const实参。
非const引用作为函数参数时,只能接受非const实参。
const引用跟非const引用可以构成函数重载。
const引用作为函数参数时的上述规则也适用于const指针。
#include <iostream>
using namespace std;
int sum(int &v1, int &v2) {
cout << "sum(int &v1, int &v2)" << endl;
return v1 + v2;
}
int sum(const int &v1, const int &v2) {
cout << "sum(const int &v1, const int &v2)" << endl;
return v1 + v2;
}
int main() {
// 非const实参
int a = 10;
int b = 20;
sum(a, b);
// const实参
const int c = 10;
const int d = 20;
sum(c, d);
sum(10, 20);
return 0;
}
输出结果如下:
3.右值引用
右值引用只能绑定到右值上,不能绑定到左值上。右值引用通常绑定到一些即将销毁的或一些临时的对象上。
#include <iostream>
using namespace std;
int main()
{
int&& ref1 = 10; // 正确,右值引用能绑定到右值上
int a = 100, b = 200;
int&& ref2 = a; // 错误,右值引用不能绑定到左值上
int&& ref3 = a * b; // 正确,右值引用能绑定到右值上
return 0;
}
返回非引用类型的函数、算术运算符、关系运算符、位运算符、后置递增运算符、后置递减运算符等,返回的都是右值,不能将左值引用绑定到这类表达式上,可以将常引用或右值引用绑定到这类表达式上。
#include <iostream>
using namespace std;
int main()
{
int i = 10;
int&& ref = i++; // 右值引用绑定到临时变量上,此后ref和i没有关系
i += 5;
cout << i << endl; // 16
cout << ref << endl; // 10
return 0;
}
4.std::move()函数
std::move() 的能力只有一个:把一个左值强制转换成一个右值。实际上这个函数根本就没有做移动的操作。
#include <iostream>
using namespace std;
int main()
{
int i = 10;
int&& ref = std::move(i); // 把一个左值强制转换成一个右值
i = 20;
cout << i << endl; // 20
cout << ref << endl; // 20
return 0;
}
#include <iostream>
using namespace std;
int main()
{
int&& ref1 = 100;
int&& ref2 = std::move(ref1); // 把一个左值强制转换成一个右值
ref1 = 200;
cout << ref1 << endl; // 200
cout << ref2 << endl; // 200
return 0;
}
#include <iostream>
using namespace std;
int main()
{
string src = "I love China!";
string dst = std::move(src); // string里的移动构造函数把src的内容转移到dst中去了,而不是std::move()转移的
cout << "&src = " << &src << ", src = " << src << endl;
cout << "&dst = " << &dst << ", dst = " << dst << endl;
return 0;
}
输出结果如下:
#include <iostream>
using namespace std;
int main()
{
string src = "I love China!";
string&& ref = std::move(src); // 把一个左值强制转换成一个右值
cout << "&src = " << &src << ", src = " << src << endl;
cout << "&dst = " << &ref << ", dst = " << ref << endl;
return 0;
}
输出结果如下: