右值引用 :int &&p
左值引用:即普通引用 int& p
常量左值引用:const int& p
共同点:都是变量,都是引用
区别:左值引用只能绑左值,右值引用只能绑右值,但注意右值引用同样也是变量,是左值!
常量左值引用却是个奇葩,它可以算是一个“万能”的引用类型,它可以绑定非常量左值、常量左值、右值,而且在绑定右值的时候,常量左值引用还可以像右值引用一样将右值的生命期延长,缺点是,只能读不能改。
如:
1 int f(); 2 vector<int> p(100); 3 4 int &&r1=f(); //f()返回int,是右值 5 int& r2=p[0]; //p的[]重载函数返回int&,是左值 6 int& r3=r1; //r1虽然是右值引用,但它本身是左值 7 int&& r4=p[0]*f(); //表达式结果是右值
转载一个知乎的回答:
知乎链接:https://www.zhihu.com/question/64205844/answer/217733257
std::move 并不会真正地移动对象,真正的移动操作是在移动构造函数、移动赋值函数等完成的,std::move 只是将参数转换为右值引用而已(相当于一个 static_cast)。
std::string str = "test"; string&& r = std::move(str);//只是简单的对右值引用r赋值,右值引用=右值引用,不存在移动构造!
中,其实只是定义了一个指向 str 的右值引用而已,str 并没有被移走。这时输出str还是等于“test”。
甚至:
1 int main() 2 { 3 //------------------------------------------------------------------------- 4 std::string str = "test"; 5 std::string&& r=move(str);//r是一个右值引用 6 string t(r);//调用拷贝构造函数,因为右值引用在表达式中自动变为左值! 7 cout<<str; 8 getchar(); 9 return 0; 10 }
这段代码输出的str依然还是"test"。因为右值引用本身实际是左值,即使r是右值引用,string t(r); 里的r仍然还是左值。所以这里调用的其实是拷贝构造函数,而不是移动构造函数。str 自然也不会被移走。
如下代码是可以真正移除str的,要么调用移动构造函数,要么调用移动赋值函数。注意情况2和情况3的区别(声明时拷贝初始化 和 先声明后赋值的区别)
1 int main() 2 { 3 //------------------------------------------------------------------------- 4 std::string str = "test"; 5 //1 6 string r1(std::move(str));//调用移动构造函数,这里把str的所有权交给了r 7 //2 8 string r2=std::move(str);//调用移动构造函数,这里把str的所有权交给了r 9 //3 10 string r3; 11 r3=std::move(str); //调用移动赋值函数,也可以把str的所有权交给r 12 //-------------------------------------------------------------------------- 13 //上面三个任意一种都可以把str真的移走 14 cout<<str; 15 getchar(); 16 return 0; 17 }
原文:https://www.cnblogs.com/FdWzy/p/12354457.html