【C/C++】C++11 Move, Forward

左值与右值

Lvalue:可以出现在 operator= 左边的

Rvalue:只能出现在operator= 右边的

int a = 1;
int a = b;
a = b;
a = a + b;
a + b = a;    // error,a + b 是右值

string s1 = "hello";
string s2 = "world";
s1 + s2 = s1;         // ok
string() = "world"    // ok

注意,虽然 string 等许多容器的临时对象可以被赋值,但编译器见到临时对象会认为它是右值

int foo() { return 3; }
...
int x = foo();     // ok
int y = &foo();    // error
foo() = 3;         // error

简单地说,能取到地址的(在内存中,而不是在寄存器中)就是右值,其余都是左值。

Rvalue Reference 右值引用

当赋值操作的右边是右值(rvalue),左边的对象不需要特意分配内存去存放这个拷贝(copy),而可以搬移(move)右边对象的资源。

用于解决不必要的拷贝和实现完美转发(perfect forwarding)。

Move Semantics 移动语义

move 相当于 浅拷贝 + 打断原指针,原来的对象无法再使用。

 

STL 许多地方使用到了右值引用和 move 语义,如 vector 中的 insert() 函数

iterator insert(const_iterator pos, const value_type& x);
iterator insert(const_iterator pos, const value_type&& x)    // 接受右值引用
{ return emplace(pos, std::move(x)); }    // 将左值变量放到std::move()中,就取得了它的右值引用

Perfect Forwading 完美转发

一个 Unperfect Forwarding 不完美转发的例子

 1 void process(int& i) {
 2     cout << "process(int&): " << i << endl;
 3 }
 4 
 5 void process(int&& i) {
 6     cout << "process(int&&): " << i << endl;
 7 }
 8 
 9 void forward(int&& i) {
10     cout << "forward(int&&): " << i << ", ";
11     process(i);
12 }
13 
14 int main() {
15     int a = 0;
16     process(a);         // process(int&): 0 
17     process(1);         // process(int&&): 1
18     process(move(a));   // process(int&&): 0
19     forward(2);         // forward(int&&): 2, process(int&): 2
20                         // Rvalue经由forward()传给另一个函数却变为Lvalue
21                         // 原因是传递过程中它变成了named object
22     forward(move(a));   // forward(int&&): 0, process(int&): 0
23 //  forward(a);         // error, cannot bind 'int' lvalue to 'int&&'
24     return 0;
25 }

 这时需要使用 std::forward<T>(),保留参数的左/右值特性

void forward(int&& i) {
    cout << "forward(int&&): " << i << ", ";
    process(std::forward<int>(i));
}

int main() {
    int a = 0;
    forward(2);         // forward(int&&): 2, process(int&&): 2
    forward(move(a));   // forward(int&&): 0, process(int&&): 0
    return 0;
} 
原文地址:https://www.cnblogs.com/wayne793377164/p/9106445.html