C++11:move移动语义

前言

我们知道移动语义是通过右值引用来匹配临时值,那么,普通的左值是否也能借助移动语义来优化性能呢,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();
A a;
a = foo();

最后一行将会发生如下操作:

  • 销毁a所持有的资源
  • 复制foo返回的临时对象所拥有的资源
  • 销毁临时对象,释放其资源

上面的办法是可行的,但是更有效的方法是直接交换a和临时对象中的资源指针,然后让临时对象的析构函数去销毁a原来拥有的资源。当复制操作符的右边是右值的时候,我们希望赋值操作符被定义成下面这样:

A & A::operator=const A &&rhs)
{
//转移资源的控制权,无需复制
}

仅仅转移资源的所有者,将资源的拥有者改为被赋值者,这就是move语义。

如下示例,假设一个临时容器很大,赋值给另一个容器:

{
	std::list<std::string> arrs;				//省略初始化
	std::list<std::string> temp = arrs;
}

std::list<std::string> arrs;				
std::list<std::string> temp = std::move(arrs);

如果这里不用move,拷贝的代价很大,性能较低。而使用move几乎没有任何代价,只是将资源的所有权转移了,实际上是将左值变成了右值引用,然后应用move语义调用构造函数,这样避免了拷贝,提高程序性能。

当一个对象内部有较大的堆内存或者动态数组时,很有必要写move语义的拷贝构造函数和赋值函数,避免无谓的深拷贝,以提高性能。

注意:move对于拥有形如对内存、文件句柄等子资源的成员的对象有效,如果是一些基本类型, 如int和char[4]数组时,如果使用move,仍然会发生拷贝(因为没有对应的移动构造函数),所以说move对于含资源的对象来说更有意义。

参考:《深入应用C++11》

相关推荐
©️2020 CSDN 皮肤主题: 代码科技 设计师:Amelia_0503 返回首页