程序员C++2.0

C++右值引用和移动语义学习小结

2018-08-25  本文已影响5人  linjinhe

在 C++11 之前,将一个对象移动(move)到另一个对象的通用做法只有 copy constructor 或者 copy assignment ,然后销毁原来的对象。如果这个对象的创建涉及动态内存分配的话,copy constructor 或者 copy assignment 的开销就可能比较大。

从 C++11 开始,C++ 引入了移动语义(move semantics)。由此 C++11 的 class 也多了两个特殊的成员函数 —— move constructor 和 move assignment。
引入移动语义,首先要做的第一件事就是,如何确定该用 move 还是 copy ?
为此 C++11 引入了右值引用这个概念 —— 在 C++ 里所有的右值都可以被移动。

这里又有了另一个问题:什么是右值引用、右值?相对的还有左值引用、左值?
左值与右值这两概念是从 C 语言中传承而来的。在 C 语言中,左值指的是既能够出现在等号左边也能出现在等号右边的变量(或表达式),右值指的则是只能出现在等号右边的变量(或表达式)。
左值可以取到其内存地址,右值不能。左值与右值的根本区别在于能否获取内存地址。
左值引用和右值引用,其实就是左值的引用和右值的引用。他们俩都是引用,区别在于引用的数据是啥。
注意,左值引用和右值引用都是左值。

下面举几个简单的列子:

int i = 42;                 // i 是个左值,42 是个右值
int& r = i;                 // r 是个左值引用
int&& rr = i;               // 错误,不能将左值 i 绑定到右值引用 rr 上
int&& rr1 = std::move(i);    // std::move 将 i 强制转换成一个右值
int &r2 = i * 42;           // 错误: i * 42 是一个右值,不能绑定到一个左值引用
const int &r3 = i * 42;     // 可以将一个右值绑定到一个 const 的左值引用
int &&rr2 = i * 42;         // 将右值绑定到右值引用

从上面的例子可以看到,有两种引用可以绑定到右值:const 左值引用和右值引用

当传入的对象是右值且支持 move constructor 或 move assignment 时,C++ 会使用移动语义的函数。如果不支持移动语义的函数,无论传入的对象是右值还是左值,C++ 还是会使用复制语义的函数。
因为左值引用和右值引用其实都是左值, C++11 提供了一个函数 std::move 可以将一个对象强制转换成右值(rvalue)。

移动语义的出现,一方面可以让编译器在某些情况下,使用 move 而不是 copy 来提升程序性能。另一方面,让一些 move-only 的类型在语义上更加明确,如 std::unique_ptrstd::futurestd::thread

更多关于右值引用、移动语义的内容,请参考

最后,附上之前整理的电子书下载链接:C++ 学习资料整理(电子书)

上一篇下一篇

猜你喜欢

热点阅读