右值引用和移动操作是C++11提出的新概念,通过这些操作,可以降低拷贝操作带来的消耗。先来简单介绍一下左值和右值。
左值一般指的是一个对象,或者说是一个持久的值,例如赋值的返回值、下标操作、解引用以及前置递增等。
右值是一个短暂的值,比如一个表达式的求值结果、函数返回值以及一个字面值等。
为了区分,把一般的引用称为左值引用,必须绑定到右值的引用称为右值引用,以&&表示。右值引用有这两个特性:
右值引用只能绑定到临时对象,所引用的对象将要被销毁,并且没有其他用户。
这也意味着,我们可以自由地接管引用对象的资源。
通常一个变量可以认为是左值,也即是一个对象。那么如何获得右值呢?可以显示转换为对应的右值引用,也可以调用标准库函数std::move()。
move()承诺了我们不再使用移后源,不保证移后源的状态和值。
实际上,移动操作窃取了对象资源的控制权,从而避免了不必要的拷贝。
int i = 1; int&& rr = std::move(i);
移后源对象必须是可以析构的,并且要保证对象依然有效,可以被赋予新值,但是不保证移后源对象中留下的值。
事实上,单纯调用std::move()并不会对对象进行改变,只有另外一个对象接管了资源后,移动才真正完成。
<<C++ primer>>在模板操作中详细解释了std::move的具体实现和工作。
template<typename T> typename remove_reference<T>::type&& move(T&& t) { return static_cast<typename remove_reference<T>::type&&> (t); }
move的参数是一个T&&,而任何有名字的参数实际上都是左值。也就是说,这个参数可以和任何类型的参数匹配,可以传左值也可以传右值。