c++的左值(lvalue),右值(rvalue),移动语义(move),完美转发(forward)
c++的左值,右值 精辟总结
当一个对象被用作右值的时候,使用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存中的位置)左值右值,完美转发参考文档。
左值持久,右值短暂;move:显示地将一个左值转换为对应右值的引用类型,还可以获取绑定到左值上的右值引用,int&& rr3 = std::move(rrl); 使用move就意味着除了对rrl赋值或销毁它外,我们不再使用它。
std::forward()与std::move()相区别的是,move()会无条件的将一个参数转换成右值,而forward()则会保留参数的左右值类型,可以使用std::forward实现完美转发。
移动语义解决了无用拷贝的问题:移动构造函数;
右值引用:函数的返回值。
int& 左值引用
int&& 右值引用
c++中无用拷贝的情况
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 28 29 30 31 32 33 34 35 36 37 38
|
class Test { public: string desc; int * arr{nullptr}; Test():arr(new int[5000]{1,2,3,4}) { cout << "default constructor" << endl; } Test(const Test & t) { cout << "copy constructor" << endl; if (arr == nullptr) arr = new int[5000]; copy(t.arr,t.arr+5000, arr); } ~Test(){ cout << "destructor " << desc << endl; delete [] arr; } };
Test createTest() { return Test(); }
int main(){
Test reusable; reusable.desc = "reusable"; Test duplicated(reusable); duplicated.desc = "duplicated";
Test t(createTest()); t.desc = "t";
cout<<"end"<<endl; }
|
运行结果
1 2 3 4 5 6 7
| default constructor copy constructor default constructor end destructor t destructor duplicated destructor reusable
|
使用移动语义避免无用的拷贝
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
|
class Test { public: string desc; int * arr{nullptr}; Test():arr(new int[5000]{1,2,3,4}) { cout << "__default constructor" << endl; } Test(const Test & t) { cout << "__copy constructor" << endl; if (arr == nullptr) arr = new int[5000]; copy(t.arr,t.arr+5000, arr); } Test(Test && t): arr(t.arr) { cout << "__move constructor" << endl; t.arr = nullptr; } ~Test(){ cout << "..destructor " << desc << endl; delete [] arr; } };
Test createTest(string str) { Test rt; rt.desc = str; cout<<"createTest:"<<&rt<<endl; return rt; }
void main(){ Test reusable; reusable.desc = "reusable"; cout<<"reusable.arr "<<reusable.arr<<endl; Test duplicated(std::move(reusable)); duplicated.desc = "duplicated"; cout<<"reusable.arr "<<reusable.arr<<endl; cout<<"duplicated.arr "<<duplicated.arr<<endl;
cout<<"rvalue--"<<endl; Test&& rt1 = createTest("rval"); cout<<"rt1.arr "<<rt1.arr<<endl; cout<<"no rvalue--"<<endl; Test rt2 = createTest("normalVal"); cout<<"createTest:"<<&rt2<<endl; cout<<"rt2.arr "<<rt2.arr<<endl;
cout<<"end"<<endl; }
|
输出结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| __default constructor reusable.arr 0x56521b946e70 __move constructor reusable.arr 0 duplicated.arr 0x56521b946e70 rvalue-- __default constructor createTest:0x7ffd092ea390 rt1.arr 0x56521b94c0b0 no rvalue-- __default constructor createTest:0x7ffd092ea3c0 createTest:0x7ffd092ea3c0 rt2.arr 0x56521b950ee0 end ..destructor normalVal ..destructor rval ..destructor duplicated ..destructor reusable
|
左值引用右值引用
1 2 3 4 5 6 7 8 9 10 11
| void foo(const int & i) { cout << "const int & " << i << endl; } void foo(int & i) { cout << "int & " << i << endl; } void foo(int && i) { cout << "int && " << i << endl; } void foo(const int && i) { cout << "const int && " << i << endl; } void main(){ int i = 2; foo(i); foo(2); foo([]()->const int && {return 2;}()); }
|
完美转发
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
class Test { public: int * arr{nullptr}; Test():arr(new int[5000]{1,2,3,4}) { cout << "default constructor" << endl; } Test(const Test & t) { cout << "copy constructor" << endl; if (arr == nullptr) arr = new int[5000]; copy(t.arr,t.arr+5000, arr); } Test(Test && t): arr(t.arr) { cout << "move constructor" << endl; t.arr = nullptr; } ~Test(){ cout << "destructor" << endl; delete [] arr; } };
template <typename T> void func(T t) { cout << "in func" << endl; }
template <typename T> void relay(T&& t) { cout << "in relay" << endl; func(t); }
template <typename T> void relay1(T&& t) { cout << "in relay " << endl; func(std::forward<T>(t)); }
void main() {
relay1(Test()); cout<<"end"<<endl;
}
|