AnI*_*ind 6 c++ vector unique-ptr move-semantics emplace
下面的最小工作示例在使用选项 1 或选项 2下的代码时编译,但在使用选项 3 下的代码时不编译。我假设emplace_back()隐式使用/调用move构造函数,那么为什么需要显式move()?跟r-valuevs. 有关系l-value吗?或者这是否与std::unique_ptr需要转让所有权有关?(我对这些概念还是陌生的,尤其是在这种情况下。)
为了完整push_back()起见,除非move()调用,否则选项 4 with也不会编译。
#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;
}
Run Code Online (Sandbox Code Playgroud)
注意:我不认为这是关于将参数传递给函数的问题的重复unique_ptr,即使链接问题的答案很有用,因为这是要求unique_ptr 在函数内定义 a然后将其移动到成员,vector以便它不会在函数结束时销毁,而且emplace_back()在此上下文中专门询问。
此外,我认为在这种情况下给出解释会很有用,因为有时很难将解释从一种情况翻译成另一种情况。谢谢!
我假设
emplace_back()隐式使用/调用移动构造函数
对不起,但你的假设是错误的。emplace_back就地构造向量中的对象,即不是从其参数复制/移动对象,而是直接构造元素,从而避免了复制/移动构造函数。
现在,如果您使用相同(但另一个)对象构造对象,那么当然会使用复制或移动构造函数,这就是您的情况。
那么为什么一个明确的
move()必要
因为你不能复制一个std::unique_ptr. 基本上,emplace_back做一些类似于这样的事情:
new (place) T(std::forward<Ts>(args)...);
Run Code Online (Sandbox Code Playgroud)
就像你这样做了:(T a(std::forward<Ts>(args)...)仅用于构建,它实际上并没有做同样的事情)。
现在它可能更明显一点:
T option1(std::move(pBeta)); // ok, move
T option3(pBeta); // error, copy
Run Code Online (Sandbox Code Playgroud)
跟
r-valuevs. 有关系l-value吗?或者这是否与std::unique_ptr需要转让所有权有关?
嗯,在某种程度上,是的。std::unique_ptr需要明确的所有权转让,这就是为什么副本被禁用而移动不是(你仍然想转让所有权!副本可能无处不在 - 为什么std::auto_ptr被弃用,然后被删除)。默认情况下,右值使用移动语义,而左值则不使用。通过使用std::move,您正在进行从左值到纯右值的转换,有效地“隐藏”了您拥有左值的事实,并且编译器会很高兴地从它那里移开。
| 归档时间: |
|
| 查看次数: |
2143 次 |
| 最近记录: |