理解右值语义
个人对右值语义的理解
理解右值语义
右值语义是C++11引入的一项特性,本文从个人理解的角度来解释右值语义的作用,希望能对您有帮助。
要理解右值语义,首先需要知道对象与资源。一个对象可能持有一个资源,或者不持有资源。
1 | class Object { |
当你传值去构造一个对象时,按照值语义,构造出来的对象与原对象之间是相互独立的,即对构造出来的对象进行任意修改都不应影响到原对象。(想想看,在传值一个int的时候,对形参的改变会影响到实参吗?)所以,当你写复制构造函数和重载复制赋值运算符时,应该进行一次深拷贝,对应到动态内存管理中,就是自己需要再分配一块动态内存,并将原动态内存上的值相对应的复制过来。
所以我们为什么需要区分左值右值呢?因为一个左值往往代表着后面还需要使用它(它可以被后续使用到,它仍能被标识),而右值意味着使用机会只有这一次(它没有被标识,后续根本无法引用它)。在这个地方,我们就可以对右值进行一次性能优化,既然对象将要消亡,我们应该把对象持有的资源“移动”到需要它的地方。落实到动态内存管理中,我们可以进行一次浅拷贝,并直接将原对象指针置为空,这样就节省了一次内存分配与释放的开销。
1 | Object a = Object(new int(1)); |
解决方案是对值语义进行一次扩充,我们需要区分左值与右值,在传递左值与右值时进行两组不同的操作。通过加入右值引用,我们可以重载出移动构造函数和移动赋值运算符。对于左值,我们可以使用复制类型的函数保证独立性,对于右值,我们可以使用移动类型的函数提升其效率。在传递容器时,这显得相关重要,因为每一次深拷贝的开销都将是巨大的。
延申阅读
eg1. C++11中将值类型具体分为了左值,将亡值,纯右值。
eg2. 对于左值最后一次使用,可以使用std::move提高效率,它将一个左值转换为右值。
eg3. 通过左值引用,右值引用类型可以区分左值右值,结合C++模板推导规则,搞出了万能引用,通过将左值右值信息编码在类型信息中,实现了完美转发。
eg4. 常见的场景中,一般在函数出参入参会牵涉到右值语义的问题,详细见Effective Modern C++ 条款25