来源
C++中的左值和右值其实是一个很久远的概念,但是逐渐到C++11才被重视起来。如今理解这两个概念对于正确运用C++11的一些特性十分有帮助。
首要要知道这两个名词其实是继承C语言,C语言中是可以简单理解为:左值是赋值语句的左侧,右值则不能。然而在C++中,则不能简单的这么认为,但是可以归纳为:当一个对象被用作右值的时候,用的是对象的值(内容),当对象被用作左值的时候,用的是对象的身份(即在内存中的位置)。
对于C++中的基本数据类型而言,基本和C语言中的使用相似,但是如果是自定义类型,则不同。
1) 对于基础类型,右值是不可被修改的,也不可被 const, volatile 所修饰
2) 对于自定义的类型,右值却允许通过它的成员函数进行修改。
#include <iostream>
using namespace std;
class Test{
public:
Test(int a):_a(a){ }
inline void show() const{
cout<<_a<<endl;
}
inline void change(int a) {
_a=a;
}
private:
int _a=3;
};
int main(){
int lvalue=int(4);
//int(3)=lvalue;这样是不行的,int(3)产生一个基础类型右值,是不可修改的
cout<<lvalue<<int(5)<<endl;
Test(5).change(6);//自定义类型右值可以通过成员函数修改
const Test& tmp=Test(7);
}
右值的两个基本特性:
1) 允许调用成员函数。
2) 只能被 const reference 指向。
一个重要的原则是当需要右值的地方可以用左值来替代,但是不能把右值当成左值(也就是位置)使用。同时,左值与右值最大的区别:左值持久,右值短暂。左值可以有持久的状态,而右值要么是字面常量,要么是表达式求值过程中创建的临时对象。
左值引用和右值引用
理解了左值和右值的基本概念和特点,就来区分一下C++11的新特性:左值引用和右值引用。对于常规的引用操作,就是左值引用,注意其不能绑定到要求转换的表达式、字面常量或是返回右值的表达式。
右值引用是必须绑定到右值的引用,通过&&来表示,其重要的特质是只能绑定要一个即将销毁的对象,即可以绑定到要求转换的表达式、字面常量或是返回右值的表达式,不能将右值绑定到一个左值上(但是可以通过move来获得绑定到左值上的右值引用)。
int i = 42; //变量是左值
int &r = i;
int &&rr = i;//错误,不能将一个右值绑定到一个左值
int &r2 = i*42;//错误,i*42是右值
const int &r3 = i*42//正确,可以将一个const引用绑定在右值上
int &&rr2 = i*42;//正确
std::move
首先要说明一下,由于移动源对象具有不确定的状态,对于std::move的使用是有风险的,在使用的时候,一定要确保move对象没有其他用户,虽然使用move可以大幅度提升性能,但是也有可能产生难以查找的错误。
一般我们对左值进行拷贝,对右值进行移动。std::move将左值转换成右值,并赋予它“可移动的语义”
#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
std::string str = "Hello";
std::vector<std::string> v;
// 使用 push_back(const T&) 重载,
// 表示我们将带来复制 str 的成本
v.push_back(str);
std::cout << "After copy, str is \"" << str << "\"\n";
// 使用右值引用 push_back(T&&) 重载,
// 表示不复制字符串;而是
// str 的内容被移动进 vector
// 这个开销比较低,但也意味着 str 现在可能为空。
v.push_back(std::move(str));
std::cout << "After move, str is \"" << str << "\"\n";
std::cout << "The contents of the vector are \"" << v[0]
<< "\", \"" << v[1] << "\"\n";
}
//输出结果
//After copy, str is "Hello"
//After move, str is ""
//The contents of the vector are "Hello", "Hello"
参考 《C++ Primer》