【问题标题】:passing as rvalue reference vs double-move value作为右值引用与双移动值传递
【发布时间】:2018-07-24 15:28:00
【问题描述】:

假设我有以下课程:

class foo {  
    std::unique_ptr<blah> ptr;
}

这两者有什么区别:

foo::foo(unique_ptr p) 
   : ptr(std::move(p))
{ }

foo::foo(unique_ptr&& p)
   : ptr(std::move(p)
{ }

当被调用时

auto p = make_unique<blah>();
foo f(std::move(p));

两者都编译,我猜两者都必须使用unique_ptr 的移动构造函数?我猜第一个它会被移动两次,但第二个它只会被移动一次?

【问题讨论】:

  • std::move 是一个简单的右值转换,它实际上并没有在后面做任何事情
  • 这能回答你的问题吗? stackoverflow.com/q/8114276/241631你说得对,第二个有2个动作,一个用于构造参数,然后用于构造数据成员。

标签: c++ c++11 move-semantics


【解决方案1】:

他们做同样的事情,即移动指针两次(转换为 2 次强制转换)。 唯一实际的区别是,如果您按值传递 std::unique_ptr,代码会中断的地方。

拥有foo::foo(unique_ptr p) 编译器会抱怨复制构造函数被删除。

如果有foo::foo(unique_ptr&amp;&amp; p),则表示所提供的参数集没有匹配的函数。

【讨论】:

    【解决方案2】:

    std::unique_ptr 是一个不可复制的类,这意味着您可以传递一个常量引用(只读访问)或移动它(右值)来表达/授予所有权。

    第二种情况(获取显式右值)是正确的实现,因为您的意图是传递所有权并且std::unique_ptr 已删除复制分配/构造函数。

    在第一种情况下,禁止复制并且 arg 是一个右值(您在传递之前移动了它),因此编译器使用移动构造函数。然后所有权属于新参数,您再次将其移动到内部字段再次传递所有权,这不是一个很好的解决方案。 (请注意,此声明不是限制性的,它允许任何值类型。如果 std::unique_ptr 是可复制的,则此处将使用复制构造函数,隐藏实际问题)。

    就结果代码而言,std::move 是一个简单的右值强制转换,所以两者都做同样的事情。在正确性方面,必须使用第二个。

    【讨论】:

    • 虽然在 C++ 社区中对此存在一些分歧,但有一些真正知识渊博的人(如 Herb Sutter)主张按值传递 unique_ptr 以指示“接收器”参数。它清楚地显示了程序员(接收器)的意图,因为它确保一旦这样传递,指针就可以保证被移动。有人可能会争辩说,右值引用解决方案更有效,因为它涉及更少的 1 个构造函数调用(构造参数所需的那个),但在我看来,说“必须使用第二个”是不合理的。因此投反对票。
    猜你喜欢
    • 2016-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-06
    相关资源
    最近更新 更多