【问题标题】:Using std::move inside a move constructor在移动构造函数中使用 std::move
【发布时间】:2016-05-04 10:11:39
【问题描述】:

This answer 像这样编写移动构造函数:

dumb_array(dumb_array&& other)
        : dumb_array() // initialize via default constructor, C++11 only
    {
        swap(*this, other);
    }

注意:这个swap 是一个自定义交换,也在类上定义,而不是std::swap

This answer 建议使用std::move

你应该只在适当的地方调用 std::move,但这是个人喜好进来的。

我刚刚观看了 Scott Meyers 关于移动语义的演讲,他说作为函数参数的 rvalue 引用由于它现在被命名,因此被转换为左值,因此 std::move有必要再次将其转回右值

换句话说,上面的代码很可能不会进行移动操作,而且与上面的引用不同,在这种情况下使用std::move 不是出于个人偏好,而是为了实际获得移动语义的好处。

如果 std::move 没有在移动构造函数或移动赋值运算符中显式使用,那么是否准确地说,移动可能实际上并没有发生,而是正在完成复制?

【问题讨论】:

  • @erip 因为我们基于标准而不是基于实现(理想情况下)编写代码,所以应该不难说出标准建议我们做什么。 Meyers 说 std::move 最常见的用法是在一个函数内部引用一个右值参数,但我很少在在线示例中看到这样做
  • 澄清一下,您问的是使用move 而不是swap?与同时使用两者相反,swap(*this, move(other)) ?后者当然毫无意义,但它可能有助于真正澄清替代方案是什么

标签: c++11


【解决方案1】:

如果 std::move 没有在移动构造函数或移动赋值运算符中显式使用,是否准确地说,移动可能实际上并没有发生,而是正在完成复制?

不,这肯定是不准确的。在问题的特定情况下,它完全取决于swap的实现。

一个自然的实现是swap(dumb_array&, dumb_array&),它在内部交换一些指针,可能是这样的:

void swap(dumb_array &lhs, dumb_array &rhs)
{
  std::swap(lhs.pointer_to_data, rhs.pointer_to_data);
}

如果是这种情况,那么您展示的移动构造函数肯定会执行轻量级移动——只是指针交换。其次,在调用swap 时使用std::move 是完全错误的,因为swap 采用左值引用。

【讨论】:

    【解决方案2】:

    我刚刚观看了 Scott Meyers 关于移动语义的演讲,他说作为函数参数的右值引用由于现在被命名这一事实而被转回为左值,因此 std::move 一次是必要的再次将其转回右值。

    没错。

    但是围绕这个话题有很多误解。

    换句话说,上面的代码很可能没有做移动操作

    它不会采取行动。但是,swap 很可能无论如何都是一种高效的操作,因此您不必在意。

    在这种情况下使用 std::move [...] 是为了真正获得移动语义的好处。

    不正确。即使您使用std::move,也不能保证会发生任何移动。

    如果 std::move 没有在移动构造函数或移动赋值运算符中显式使用,那么是否准确地说,移动可能实际上并没有发生,而是正在完成复制?

    即使没有std::move,也会发生移动。

    所以基本上,std::move 对于移动的发生既不是必要的,也不是充分的。这可能看起来很令人惊讶。


    我认为这真的没有捷径可走。如果您想了解这一点,请找到一个很好的综合教程。例如。 Thomas Becker 的热门 C++ Rvalue References Explained

    【讨论】:

      猜你喜欢
      • 2015-02-14
      • 2014-03-13
      • 2013-01-22
      • 2013-01-24
      • 2012-06-12
      • 2015-03-21
      • 2013-12-08
      • 1970-01-01
      • 2020-12-30
      相关资源
      最近更新 更多