为什么在此示例中需要使用 emplace_back 进行移动?
Why is move necessary with emplace_back in this example?
以下最小工作示例在使用选项 1 或选项 2 下的代码时编译,但在使用选项 3 下的代码时不编译。我假设 emplace_back()
隐式 uses/calls 一个 move
构造函数,那么为什么需要显式 move()
呢?它与 r-value
与 l-value
有什么关系吗?还是这与 std::unique_ptr
需要转让所有权有关? (我对这些概念还是陌生的,尤其是在这种情况下。)
为了完整起见,带有 push_back()
的选项 4 也不会编译,除非调用 move()
。
#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
参数传递给函数的 this question 的重复,即使链接的答案问题很有用,因为这是询问在 函数中定义 unique_ptr
然后将其移动到成员 vector
以便它不会在最后被销毁功能的,此外,在这种情况下特别询问 emplace_back()
。
此外,我认为在这种情况下给出解释会很有用,因为有时很难将解释从一种情况翻译成另一种情况。谢谢!
I was under the assumption that emplace_back()
implicitly uses/calls a move constructor
抱歉,您的假设是错误的。 emplace_back
就地构造向量中的对象,即不是 copying/moving 从其参数中构造对象,而是直接构造元素,从而避免了 copy/move 构造函数。
现在,如果您使用相同(但另一个)对象构造对象,那么当然会使用复制构造函数或移动构造函数,这就是您的情况。
so why is an explicit move()
necessary
因为你不能复制一个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
Does it have something to do with r-value
vs. l-value
? Or does this have to do with std::unique_ptr
needing to transfer ownership?
嗯,在某种程度上,是的。 std::unique_ptr
需要明确的所有权转移,这就是为什么复制被禁用而移动没有被禁用的原因(你仍然想转移所有权!而且复制可以随处发生 - 为什么 std::auto_ptr
被弃用,然后被删除)。默认情况下,右值使用移动语义,而左值则不使用。通过使用 std::move
,您正在进行从左值到纯右值的转换,有效地 "hiding" 您拥有左值的事实,编译器将很乐意从它转移。
以下最小工作示例在使用选项 1 或选项 2 下的代码时编译,但在使用选项 3 下的代码时不编译。我假设 emplace_back()
隐式 uses/calls 一个 move
构造函数,那么为什么需要显式 move()
呢?它与 r-value
与 l-value
有什么关系吗?还是这与 std::unique_ptr
需要转让所有权有关? (我对这些概念还是陌生的,尤其是在这种情况下。)
为了完整起见,带有 push_back()
的选项 4 也不会编译,除非调用 move()
。
#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
参数传递给函数的 this question 的重复,即使链接的答案问题很有用,因为这是询问在 函数中定义 unique_ptr
然后将其移动到成员 vector
以便它不会在最后被销毁功能的,此外,在这种情况下特别询问 emplace_back()
。
此外,我认为在这种情况下给出解释会很有用,因为有时很难将解释从一种情况翻译成另一种情况。谢谢!
I was under the assumption that
emplace_back()
implicitly uses/calls a move constructor
抱歉,您的假设是错误的。 emplace_back
就地构造向量中的对象,即不是 copying/moving 从其参数中构造对象,而是直接构造元素,从而避免了 copy/move 构造函数。
现在,如果您使用相同(但另一个)对象构造对象,那么当然会使用复制构造函数或移动构造函数,这就是您的情况。
so why is an explicit
move()
necessary
因为你不能复制一个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
Does it have something to do with
r-value
vs.l-value
? Or does this have to do withstd::unique_ptr
needing to transfer ownership?
嗯,在某种程度上,是的。 std::unique_ptr
需要明确的所有权转移,这就是为什么复制被禁用而移动没有被禁用的原因(你仍然想转移所有权!而且复制可以随处发生 - 为什么 std::auto_ptr
被弃用,然后被删除)。默认情况下,右值使用移动语义,而左值则不使用。通过使用 std::move
,您正在进行从左值到纯右值的转换,有效地 "hiding" 您拥有左值的事实,编译器将很乐意从它转移。