什么是std :: move(),什么时候应该使用?

  1. 它是什么?
  2. 它有什么作用?
  3. 什么时候使用?

良好的联系表示赞赏。

http://en.wikipedia.org/wiki/C%2B%2B11#Rvalue_references_and_move_constructors
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2027.html#Move_Semantics

  1. 在C ++ 11中,除了复制构造函数之外,对象还可以有移动构造函数。
    (除了复制赋值操作符外,还有赋值操作符。)
  2. 如果对象具有types“rvalue-reference”( Type && ),则使用移动构造函数代替复制构造函数。
  3. std::move()是一个对对象产生右值引用的强制转换,以便从中移动。

这是一种新的C ++避免副本的方式。 例如,使用移动构造函数, std::vector可以将其内部指针复制到新对象的数据,使移动的对象处于不正确的状态,从而避免复制所有数据。 这将是C ++ – 有效。

尝试search移动语义,右值,完美的转发。

当你需要将某个对象的内容“转移”到别的地方时,你可以使用move,而不需要复制(例如内容不重复,这就是为什么它可以用在一些不可复制的对象上,比如unique_ptr)。 对象也可以不用拷贝(并且保存很多时间)来获取临时对象的内容,而使用std :: move。

这个链接真的帮助我:

http://thbecker.net/articles/rvalue_references/section_01.html

我很抱歉,如果我的答案迟到了,但是我也在为std :: move寻找一个好的链接,并且我发现上面的链接有点“严峻”。

这就把重点放在了r值参考上,在这个环境下你应该使用它们,我认为它更详细,这就是为什么我想在这里分享这个链接。

“这是什么?”

虽然std::move() “看起来像”一个函数 – 我会说这不是一个真正的函数 。 这是编译器考虑expression式值的方式之间的一种转换器。

2.“它做了什么?

首先要注意的是, std::move() 并不实际移动任何东西

如果你曾经看过animation系列“ 漂白” – 它的确和昆西· 西尔·施耐德的灵魂柔化相当(另见它在这个场景中的使用)。

但是,严重的是,它将expression式从左值或纯右值 (例如,您可能已经使用了很长时间的variables,或者临时传递了一段时间)转换为x值 。 一个xvalue告诉编译器:

你可以掠夺我, 移动任何我持有的东西,并在别处使用它(因为我将很快被销毁)“。

换句话说,当你使用std::move(x) ,你允许自己(或者编译器)调用x 。 所以,如果x在内存中拥有自己的缓冲区 – 在std::move()您可以使用该缓冲区来处理任何您喜欢的事情。

3.“什么时候应该使用?”

提出这个问题的另一种方法是“我将使用什么/蚕食对象的资源?” 好吧,如果你正在编写应用程序代码,那么你可能不会用编译器创build的临时对象搞乱很多。 所以主要是你可以在像构造函数,运算符方法,类似STLalgorithm的函数等其他地方做对象的创build和销毁。 当然,这只是一个经验法则。

一个典型的用途是将资源从一个对象移动到另一个对象而不是复制。 @Guillaume链接到这个页面 ,它有一个简单的例子:用较less的拷贝交换两个对象。

 template <class T> swap(T& a, T& b) { T tmp(a); // we now have two copies of a a = b; // we now have two copies of b (+ discarded a copy of a) b = tmp; // we now have two copies of tmp (+ discarded a copy of b) } 

使用移动可以交换资源,而不是复制它们:

 template <class T> swap(T& a, T& b) { T tmp(std::move(a)); a = std::move(b); b = std::move(tmp); } 

想想当T是大小为n的vector<int>时会发生什么。 在第一个版本中,您读取和写入3 * n个元素,在第二个版本中,您基本上只读取和写入向量缓冲区的3个指针。 Tclass当然需要知道如何做这个动作; 你应该有一个移动赋值运算符和一个T类的移动构造函数来实现这个function。

std :: move本身并没有太多的作用。 我认为它调用了一个对象的移动构造函数,但它只是执行一个types转换(将一个左值variables转换为右值,以便该variables可以作为parameter passing给移动构造函数或赋值运算符)。

所以std :: move只是作为使用移动语义的先驱。 移动语义本质上是处理临时对象的有效方法。

考虑对象A = B + C + D + E + F;

这是很好看的代码,但E + F产生一个临时对象。 然后D + temp产生另一个临时对象,依此类推。 在一个类的每个正常的“+”运算符中,发生深度复制。

例如

 Object Object::operator+ (const Object& rhs) { Object temp (*this); // logic for adding return temp; } 

在这个函数中创build临时对象是没有用的 – 这些临时对象在行结束时会被删除,因为它们超出了范围。

我们可以使用移动语义来“掠夺”临时对象并做类似的事情

  Object& Object::operator+ (Object&& rhs) { // logic to modify rhs directly return rhs; } 

这避免了不必要的深拷贝。 参考这个例子,深度复制的唯一部分是E + F。其余部分使用移动语义。 移动构造函数或赋值运算符也需要实现,以将结果分配给A.

1)什么? std::move()是C ++标准库中用于转换为右值引用的函数。

简单地说, std::move(t)相当于:

 static_cast<T&&>(t); 

右值是一个临时值,它不会超出定义它的expression式,例如永远不会存储在variables中的中间函数结果。

 int a = 3; // 3 is a rvalue, does not exist after expression is evaluated int b = a; // a is a lvalue, keeps existing after expression is evaluated 

在N2027:“Rvalue引用简介”中给出了std :: move()的实现,如下所示:

 template <class T> typename remove_reference<T>::type&& std::move(T&& a) { return a; } 

正如你所看到的, std::move无论是用值( T ),引用types( T& )还是右值引用( T&& )调用,都会返回T&&

2.)它有什么作用? 作为一个演员,它在运行时不会做任何事情。 只有在编译时才告诉编译器,你想继续把这个参考看作是一个右值。

 foo(3 * 5); // obviously, you are calling foo with a temporary (rvalue) int a = 3 * 5; foo(a); // how to tell the compiler to treat `a` as an rvalue? foo(std::move(a)); // will call `foo(int&& a)` rather than `foo(int a)` or `foo(int& a)` 

不能做什么:

  • 复制一个参数
  • 调用复制构造函数
  • 更改参数对象

3.)什么时候应该使用? 你应该使用std::move如果你想调用不支持右值(临时expression式)参数的移动语义的函数。

这为我提出了以下后续问题:

  • 什么是移动语义? 与复制语义相比,移动语义是一种编程技术,其中对象的成员通过“接pipe”来初始化,而不是复制另一个对象的成员。 这种“接pipe”只能通过指针和资源句柄来理解,通过复制指针或整数句柄而不是底层数据可以很便宜地传送。

  • 什么样的类和对象支持移动语义? 如果开发人员在自己的类中实现移动语义,如果这些移动语句可以通过传输成员而不是复制它们,那么这取决于您。 一旦实现了移动语义,您将直接受益于许多图书馆程序员的工作,他们已经增加了对移动语义有效处理类的支持。

  • 为什么编译器不能自行解决呢? 编译器不能只调用另一个函数的重载,除非你这么说。 您必须帮助编译器select是否应该调用常规或移动版本的函数。

  • 在哪种情况下,我想告诉编译器,它应该把一个variables作为一个右值? 这很可能发生在模板或库函数中,您知道可以挽救中间结果。