【问题标题】:Move constructor on derived object在派生对象上移动构造函数
【发布时间】:2011-05-04 11:04:48
【问题描述】:

如果派生对象具有移动构造函数,并且基对象也具有移动语义,那么从派生对象移动构造函数调用基对象移动构造函数的正确方法是什么?

我首先尝试了最明显的事情:

 Derived(Derived&& rval) : Base(rval)
 { }

但是,这似乎最终调用了 Base 对象的复制构造函数。然后我在这里明确地尝试使用std::move,如下所示:

 Derived(Derived&& rval) : Base(std::move(rval))
 { }

这行得通,但我很困惑为什么它是必要的。我认为std::move 只是返回一个右值引用。但是因为在这个例子中rval 已经是一个右值引用,所以对std::move 的调用应该是多余的。但是如果我在这里不使用std::move,它只会调用复制构造函数。那么为什么需要拨打std::move 呢?

【问题讨论】:

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


    【解决方案1】:

    rval 不是右值。它是移动构造函数体内的左值。这就是为什么我们必须显式调用std::move

    请参阅this。重要的提示是

    注意上面的参数 x 是 被视为内部的左值 移动函数,即使它是 声明为右值引用 范围。这就是为什么有必要 说 move(x) 而不是 x when 传递给基类。这 是移动的一项关键安全功能 旨在防止的语义 不小心从某些地方移动了两次 命名变量。所有动作只发生 来自右值,或使用显式强制转换 右值,例如使用 std::move。如果 你有一个变量的名字,它 是一个左值。

    【讨论】:

    • 如果你提供一个作为常规左值的参数输入(不使用std::move(xx)),只需添加一个注释而不考虑移动构造函数,你将得到“无法将'Xyy'左值绑定到' Xyy&&' 用于定义为 foo(Xyy&& xyy) 的函数。
    【解决方案2】:

    命名的 R 值引用被视为 L 值。

    所以我们需要std::move 将其转换为 R-Value。

    【讨论】:

      【解决方案3】:

      你真的应该使用 std::forward(obj) 而不是 std::move(obj)。 Forward 将根据 obj 是什么返回正确的右值或左值,而 move 会将左值转换为右值。

      【讨论】:

      • 在这种情况下,您总是希望转换为右值。
      • 所以真正的意图是转发传入的内容,而不是更改传入的内容。 Forward() 正是这样做的。它还可以让您练习使用它来调用所有基本函数,无论传入什么。养成调用 move() 的习惯可能会产生难以追踪的错误。如果您想在可以同时作用于右值和左值的函数上使用模板,这也会派上用场。如果这个函数被错误地传递给一个左值对象会希望它继续执行吗?只是玩鬼鼓吹一点
      • @jbreiding 我什么都不懂...介意用一些代码示例详细说明您的解释,说明 std::move 何时会失败,为什么首选 std::forward 以及何时使用哪个?
      • @jbreiding 参见 Scott Meyers 的 Effective Modern C++,第 23 和 25 条。引用其中的一部分:“std::forward 需要函数参数和模板类型参数...我们传递给std::forward 的类型应该是非引用...这意味着std::movestd::forward 需要更少的输入,并且它省去了我们传递编码该参数的类型参数的麻烦我们传递的是一个右值。它还消除了我们传递不正确类型的可能性......这[可能]导致数据成员 [] 被复制构造而不是移动构造。”
      • std::forward 是左值和右值的脏重载助手。当您希望函数模板同时转发左值和右值时,应该使用它。这里你要做的就是调用父类move-constructor,所以std::move是更明确和直接的解决方案。
      猜你喜欢
      • 2016-10-06
      • 1970-01-01
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 2016-06-28
      • 2021-09-15
      • 1970-01-01
      • 2018-07-21
      相关资源
      最近更新 更多