移动语义是通过右值引用来匹配临时值,现在C++11提供了std::move方法来讲左值转换为右值,从而方便应用移动语义。
move是将对象的状态或者所有权从一个对象转移到另一个对象,只是转移,没有内存拷贝。
move实际上并不能移动任何东西,它唯一的功能是将一个左值强制转换为一个右值引用,使我们可以通过右值引用使用该值,以用于移动语义。强制转换为右值的目的是为了方便实现移动构造。
这种move语义是很有用的,比如一个对象中有一些指针资源或者动态数组,在对象的赋值或拷贝时就不需要拷贝这些资源了。在C++11之前拷贝构造函数和赋值函数可能要像下面这样定义。假设一个A对象内部有一个资源m_ptr:
A& A::operator=(const A& rhs)
{
///销毁m_ptr指向的资源
///复制rhs.m_ptr所指的资源,并使用m_ptr指向它
}
同样A的拷贝构造函数也是这样的。假设这样来使用A:
A foo(); ///foo是一个返回值为类A的函数
A a;
a = foo();
最后一行将会发生如下操作:
1、销毁a所持有的资源;
2、复制foo返回的临时对象所拥有的资源;
3、销毁临时对象,释放其资源。
上面的过程是可行的,但是更有效率的办法是直接交互a和临时对象中的资源指针,然后让临时对象的析构函数去销毁a原来拥有的资源。换句话说,当赋值操作符的右边是右值的时候,我们希望赋值操作符被定义成下面这样:
A& A::operator=(const A&& rhs)
{
///转移资源的控制权,无须复制
}
仅仅转移资源的所有权,将资源的拥有者改为被赋值者,这就是所谓的move语义。
如果不用std::move,拷贝的代价很大,性能较低。使用move几乎没有任何代价,只是转换了资源的所有权。实际上是将左值变成右值引用,然后应用move语义调用构造函数,就避免了拷贝,提高了程序性能。当一个对象内部有较大的堆内存或者动态数组时,很有必要写move语义的拷贝构造函数和赋值函数,避免无谓的深拷贝,以提高性能。事实上,C++中所有的容器都实现了move语义,方便我们实现性能优化。
如果是一些基本类型,比如int和char[0]数组等,如果使用move,仍然会发生拷贝(因为没有对应的移动构造函数),所以说move对于含有资源的对象来说更有意义。