繁体   English   中英

在这个例子中为什么需要使用emplace_back进行移动?

[英]Why is move necessary with emplace_back in this example?

当使用选项1或选项2下的代码时,以下最小工作示例进行编译,但在使用选项3下的代码时编译。 我假设emplace_back()隐式使用/调用move构造函数,那么为什么需要显式move()呢? 它与r-valuel-value吗? 或者这与std::unique_ptr需要转移所有权有关吗? (我仍然对这些概念不熟悉,特别是在这种情况下。)

为了完整性,除非调用move() ,否则带有push_back()选项4也不会编译。

#include <iostream>
#include <vector>
#include <memory>

class Beta {
public:
    Beta(int x, int y, int z): mX(x), mY(y), mZ(z) { };
    int mX; int mY; int mZ;

};

class Alpha {
public:
    std::vector<std::unique_ptr<Beta>> betaVec;
    void addBeta(int x, int y, int z) {
        // only choose one of the following options:
        // option 1 (compiles)
        std::unique_ptr<Beta> pBeta = std::make_unique<Beta>(x, y, z);
        betaVec.emplace_back(move(pBeta));

        // option 2 (compiles)
        betaVec.emplace_back(std::make_unique<Beta>(x, y, z));

        // option 3 (does not compile)
        std::unique_ptr<Beta> pBeta = std::make_unique<Beta>(x, y, z);
        betaVec.emplace_back(pBeta);

        // option 4 (does not compile)
        std::unique_ptr<Beta> pBeta = std::make_unique<Beta>(x, y, z);
        betaVec.push_back(pBeta);

        // option 5 (compiles)
        std::unique_ptr<Beta> pBeta = std::make_unique<Beta>(x, y, z);
        betaVec.push_back(move(pBeta));
    }
};

int main() {

    return 0;
}

注意:我不认为这是关于将unique_ptr参数传递给函数的这个问题的重复,即使链接问题的答案很有用,因为这要求函数中定义unique_ptr然后将其移动到成员vector以便它不会在函数结束时被销毁,而且,在此上下文中具体询问emplace_back()

另外,我认为在这种情况下给出解释是有用的,因为有时很难将解释从一个上下文转换到另一个上下文。 谢谢!

我假设emplace_back()隐式使用/调用移动构造函数

对不起,但你的假设是错的。 emplace_back构造了向量中的对象,即不是从对象中复制/移动对象,而是直接构造元素,避免了复制/移动构造函数。

现在,如果您使用相同(但另一个)对象构造对象,那么当然要使用复制或移动构造函数,这就是您的情况。

那么为什么需要一个明确的move()

因为你无法复制std::unique_ptr 基本上, emplace_back做了类似于此的事情:

new (place) T(std::forward<Ts>(args)...);

就像你做的那样: T a(std::forward<Ts>(args)...) (仅用于构造,它实际上并没有做同样的事情)。

现在它可能更明显一点:

T option1(std::move(pBeta)); // ok, move
T option3(pBeta); // error, copy

它与r-valuel-value吗? 或者这与std::unique_ptr需要转移所有权有关吗?

那么,在某种程度上,是的。 std::unique_ptr需要明确的所有权转移,这就是为什么副本被禁用而移动不是(你仍然希望转移所有权!并且副本可以在任何地方发生 - 为什么std::auto_ptr被弃用,然后被删除)。 右值默认使用移动语义,而左值则不使用移动语义。 通过使用std::move ,您正在进行从左值到初值的转换,有效地“隐藏”您拥有左值的事实,编译器将很乐意从它移动。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM