我构建一个以std::vector<std::unique_ptr<A> >
为参数的对象。构造函数定义如下
class B {
std::vector <std::unique_ptr<A> > e_;
public:
B(std::vector <std::unique_ptr<A> > e) : e_(std::move(e)){}
};
然后用作
std::vector <std::unique_ptr<A> > e;
B b(e);
和Xcode显示错误
error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<A, std::__1::default_delete<A> >'
:new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`
即使我使用std::move()
?
编辑:如果我使用B b(std::move(e))
而不是B b(e))
,错误似乎消失了,有没有办法将move
逻辑移动到函数的实现中?
答案 0 :(得分:5)
您的构造函数参数是按值传递的,它将复制,但您无法复制std :: unique_ptr。通过引用传递应该有效:
class B {
std::vector <std::unique_ptr<float> > e_;
public:
B(std::vector <std::unique_ptr<float> >& e) : e_(std::move(e)){}
};
但是......我同意其他评论说这是糟糕的设计。如果您希望B
拥有e
但又希望在e
之外操纵B
,那么它应该是公共成员,不需要花哨的构造函数:
class B {
public:
std::vector <std::unique_ptr<float> > e_;
};
答案 1 :(得分:1)
为什么即使我使用std :: move()?
,错误仍然存在
因为您正在将B
的ctor的参数移动到成员中,这并不意味着应该或可以移动变量e
。
有没有办法将移动逻辑移动到函数的实现?
即使有可能,也不应该这样做。对于使用e
的代码的读者应该清楚,它已被移动并且不能再使用了。
答案 2 :(得分:1)
正如前面的答案所暗示的,问题是您无法复制std::unique_ptr
。按值传递构造函数参数将触发复制。话虽这么说,如果打算让B
拥有unique_ptr
,那么正确的方法就是使用B b(std::move(e))
。
与某些评论相反,这实际上是Herb Sutter建议的设计:https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/。通过值传递unique_ptr可以清楚地表明,构造函数将对象的所有权从调用者手中夺走了。此外,由于编译器需要显式的std::move
,因此在代码中清楚地记录了语义。也就是说,对于用户来说,unique_ptr
很明显由于显式std::move
而被构造函数调用无效。