move表示可以重用对象中的资源move实质是将任何值强制转换为「右值」引用,使得「移动构造函数」可以匹配上。move需要和「移动构造函数/移动赋值运算符」一起使用才可以起到减少拷贝的作用。
move
move(a)的含义是:a中的资源可以移动到其他对象中,被再利用。
例如:
vector<string> words;string str = "123";words.push_back(move(str));cout << "after move: " << str;// "after move: "
move的原理:实质上是将类型强制转换为「右值引用 T&&」类型。
move需要配合「移动构造函数」或「移动赋值函数」一起使用:
struct Obj {// 移动构造函数Obj(Obj&& obj) {member = move(obj.member); // 再调用成员的移动构造函数}// 移动赋值运算Obj& operator=(Obj&&) {member = move(obj.member);return *this;}};
构造函数的类型
构造函数的类型:
// 默认构造函数T() {}// 复制构造函数T(const T& t) {}// 移动构造函数T(T&& t) {}
左值和右值
从 C++11开始,表达式可以按照两个维度进行划分:「是否拥有身份」和「能否被移动」。三种基本的表达式类型「亡值 xvalue」,「左值 lvalue」和「纯右值prvalue」如下所示:
| 拥有身份 (泛左值) |
不拥有身份 | |
|---|---|---|
| 可被移动 (右值) |
亡值xvalue |
纯右值prvalue |
| 不可被移动 | 左值lvalue |
- |
其中,「亡值」和「左值」合起来是「泛左值」;「亡值」和「纯右值」合起来是「右值」。
基本类型:
- 左值:
- 特点是:可以取地址;
- 左值可用于初始化「左值引用
T&」,此时相当于为表达式对象关联新的名字。 - 常见的左值:字符串字面量,变量名称构成的表达式,
++a,等
- 纯右值:
- 常见的纯右值:除字符串字面量以外的字面量,如
42, true, nullptr - 注:
a++是纯右值,而++a是左值。因此++a性能更高。
- 常见的纯右值:除字符串字面量以外的字面量,如
- 亡值:
std::move(x)是亡值。
注:右值:可被移动的值是右值,「纯右值」和「亡值」都是右值。
- 右值可用于初始化「常量左值引用
const T&」,此时对象的生命周期延长至作用域结束; - 右值可用于初始化「右值引用
T&&」,此时对象的生命周期延长至作用域结束。
例子:字符串常量作为左值:
cout << &"123" << endl; // 0x100c17e90auto & str = "123";cout << &str << endl; // 0x100c17e90
例子:变量的表达式是左值:
struct A {// 移动构造函数A(A&& a) { ... }};void foo(A&& a) {// 变量 a 是 A&& 类型的,但是// 「变量的表达式」是「左值表达式」,需要使用 move 转换为右值// 这样才能使用「右值构造函数」A a2 = std::move(a);}
