c++ 衣原菌 - 什么是std::move(),什么时候应该使用它?




chlamydia检查 igg是什么 (5)

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

良好的联系表示赞赏。


Answers

1.“它是什么?”

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

2.“它做了什么?”

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

如果你曾经看过动画系列Bleach - 它相当于Quincy Seele Schneider灵魂柔化 (另见它在这个场景中的使用)。

不过,严格来说,它将表达式从左值或纯右值 (例如,您可能已经使用很长时间的变量,或者临时传递一段时间)转换为xvalue 。 一个xvalue告诉编译器:

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

换句话说,当你使用std::move(x) ,你允许编译器打包x 。 因此,如果x在内存中拥有自己的缓冲区 - 在std::move() ,编译器可以让另一个对象拥有它。

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

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

一个典型的用途是将资源从一个对象移动到另一个对象而不是复制。 @Guillaume链接http://thbecker.net/articles/rvalue_references/section_01.htmlhttp://thbecker.net/articles/rvalue_references/section_01.html有一个简单的例子:用较少的复制交换两个对象。

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)
}

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

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个指针。 当然,T班需要知道如何进行移动; 你应该有一个移动赋值运算符和一个T类的移动构造函数,以使其工作。


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. 如果对象的类型为“rvalue-reference”( Type && ),则使用移动构造函数代替复制构造函数。
  3. std::move()是一个对对象产生右值引用的强制转换,以便从中移动。

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

尝试谷歌搜索移动语义,右值,完美的转发。


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

所以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;
}

在这个函数中创建临时对象是无用的 - 当这些临时对象超出范围时,它们将在行尾被删除。

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

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

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


当需要将某个对象的内容“转移”到其他位置时,您可以使用移动,而不进行复制(例如内容不重复,这就是为什么它可以用于某些不可复制的对象,如unique_ptr)。 也可以使用std :: move来获取临时对象的内容,而无需复制(并节省大量时间)。

这个链接真的帮助我:

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

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

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


使用dynamic_cast转换继承层次结构中的指针/引用。

使用static_cast进行普通类型转换。

使用reinterpret_cast进行低级重新解释位模式。 使用时要格外小心。

使用const_cast来抛弃const/volatile 。 除非你使用const不正确的API,否则请避免这种情况。





c++ c++11 move-semantics