此问题结合了unique_ptr as class member and move semantics fail to compile with clang和C++ std::vector in constructor。
我的目标是构建一个包装器
struct V_wrapper{
std::vector<std::unique_ptr<AClass> > vec;
V_wrapper(std::vector<std::unique_ptr<AClass> > v) : vec{std::move(v)} {}
};
不幸的是,此代码无法编译,因为编译器(clang Apple LLVM版本4.2)尝试复制构造不受支持的向量v
。另一方面,如果我为std::unique_ptr<AClass>
设计一个中间包装器,如下所示
struct P_wrapper{
std::unique_ptr<AClass> Ptr;
P_wrapper(std::unique_ptr<AClass>& p) : Ptr(std::move(p)) {}
};
并按如下方式编写V_wrapper
struct V_wrapper{
std::vector<P_wrapper > vec;
V_wrapper(std::vector<P_wrapper > v) : vec{std::move(v)} {}
};
那时我没有问题。我认为(强调)它的工作原理是向量的构造函数意识到你应该使用引用而不是试图复制,就像在unique_ptr as class member and move semantics fail to compile with clang中一样。
不幸的是,这导致了我制作std::vector<std::unique_ptr<AClass> >
的相当不方便的构造过程,使用它来构造P_wrapper
,最后用它来构造V_wrapper
。我觉得中间步骤应该是完全多余的!此外,它使界面更难阅读。首先,包装器的重点是隐藏用户的vec
实现,现在有一个莫名其妙的(不知道源代码)对象P_wrapper
,它只用于构造另一个对象....
我想避免这种情况,只有一个包装器。是否有任何方法可以切断中间人,以便我可以回到V_wrapper
的第一个更简单的实现?
答案 0 :(得分:1)
您需要删除默认的复制构造函数和赋值运算符。这些函数是隐式定义的,需要明确删除,因为它们会尝试复制向量及其内容(这是对unique_ptr
的非法操作)。
struct V_wrapper
{
public:
V_wrapper(std::vector<std::unique_ptr<AClass> > v)
: vec(std::move(v))
{}
// Delete default copy constructor + assignment operator
V_wrapper(const V_wrapper &) = delete;
V_wrapper& operator= (const V_wrapper &) = delete;
private:
std::vector<std::unique_ptr<AClass> > vec;
};
答案 1 :(得分:0)
不要无偿使用支撑剂; std::vector
有一个使用初始化列表的构造函数。写这篇文章的明显方法对我来说很好:
#include <memory> // for std::unique_ptr
#include <utility> // for std::move
#include <vector> // for std::vector
struct bar {};
struct foo
{
using vtype = std::vector<std::unique_ptr<bar>>;
foo(vtype v) : _v(std::move(v)) { }
private:
vtype _v;
};