【问题标题】:Why does this need an explicit std::move?为什么这需要一个显式的 std::move?
【发布时间】:2014-01-23 23:02:12
【问题描述】:

假设我有一个 Foo 类,其中包含一个由另一个类 std::unique_ptr 对象 Bar 构造的 std::vector

typedef std::unique_ptr<Bar> UniqueBar;

class Foo {
    std::vector<UniqueBar> bars;
public:
    void AddBar(UniqueBar&& bar);
};

void Foo::AddBar(UniqueBar&& bar) {
    bars.push_back(bar);
}

这导致编译错误(在g++ 4.8.1中)说std::unique_ptr的复制构造函数被删除,这是合理的。这里的问题是,既然 bar 参数已经是一个右值引用,为什么会调用std::unique_ptr 的复制构造函数而不是它的移动构造函数呢?

如果我在Foo::AddBar 中明确调用std::move,那么编译问题就会消失,但我不明白为什么需要这样做。我认为这很多余。

那么,我错过了什么?

【问题讨论】:

    标签: c++ c++11


    【解决方案1】:

    基本上,每个有名字的对象都是一个左值。当您使用右值引用将对象传递给函数时,该函数实际上会看到一个左值:它被命名。然而,右值引用的作用是表明它来自一个准备好被传输的对象。

    换句话说,右值引用是不对称的:

    • 它们只能接收右值,即临时对象、即将消失的对象或看起来像是右值的对象(例如,std::move(o) 的结果)
    • 然而,右值引用本身看起来像一个左值

    【讨论】:

      【解决方案2】:

      虽然看起来令人困惑,rvalue-reference 绑定到 rvalue,但用作表达式的是 lvalue。 p>

      【讨论】:

        【解决方案3】:

        bar实际上是一个左值,所以你需要通过std::move来传递它,这样在push_back的调用中它就被看作是一个右值。

        Foo::AddBar(UniqueBar&amp;&amp; bar) 重载只是确保在调用 Foo::AddBar 时传递右值时选择此重载。但是bar 参数本身有一个名称并且是一个左值。

        【讨论】:

          【解决方案4】:

          bar 被定义为一个右值引用,但它的 值类别 是一个左值。之所以如此,是因为该对象有一个名称。如果它有名字,它就是一个左值。因此明确的std::move 是必要的,因为其目的是摆脱名称并返回一个xvalue(eXpiring-rvalue)。

          【讨论】:

            猜你喜欢
            • 2012-07-28
            • 2017-06-11
            • 2015-06-25
            • 2015-05-10
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-02-16
            相关资源
            最近更新 更多