lvalue rvalue
很多人说:左值就是有地址的值
但是,不要试图用l和r来找定义。
要从实现上理解。
检测左值的方法:左值引用
string& a = "aa"; // 错误,因为"aa"是右值,不能被左值引用
string& a = string("aa"); // 错误,因为string("aa")是右值,不能被左值引用
string b = "aa";
string& a = b; //正确,因为b是左值
检测右值的方法:右值引用
std::string&& a = "aa"; //正确,这里有一个隐式转换,把"aa"转成了string("aa"),string("aa")是右值
std::string&& a = std::string("aa"); //正确,因为string("aa")是右值
std::string b = "aa";
std::string&& a = b; //错误,因为b是左值,不能被右值引用
兼容左值和右值参数的方法:常量左值引用
它实际上在做的事情是在编译器创建新的代码,如果是右值传递,把右值赋值给一个新的左值,再用左值传递给左值引用;如果是左值传递,就直接传递过来。
const string& a = "aa";
const string& a = string("aa");
初学者会遇到右值的一种情况。
string a1,a2;
a1 + a2 是右值,因为它是临时变量
所以记住,左值是由某种存储支持的变量,右值是临时值。
左值引用只能接受左值,除非用const;右值引用只能接受右值。
右值引用带给我们什么
我们现在有了一种方法来检测临时值,并对它们做一些特殊的事情。
因为它们是临时变量,我们可以从中窃取一些资源。
而const 的左值引用,你不能从里面窃取任何东西,因为它可能在很多函数中被使用。
用途比如移动语义。
移动构造函数和移动赋值运算符
String (String&& other) noexcept{} //移动构造函数
String& operator=(String&& other) noexcept{} //移动赋值运算符
String string = "Hello";
String dest = std::move(string); //移动构造了dest实例
String dest = (String&&)string; // 和上面写法等价
String dest;
dest = std::move(string); // 移动赋值给了dest
移动赋值运算符为了避免内存泄漏,需要先delete掉自己原本的内存。