1

这个问题将unique_ptr 结合为类成员,并且移动语义无法在构造函数中使用 clangC++ std::vector进行编译。

我的目标是构建一个包装器

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 作为类成员并且移动语义无法使用 clang 编译一样

不幸的是,这导致了相当不方便的构造过程,我制作std::vector<std::unique_ptr<AClass> >,用它来构造P_wrapper,最后用它来构造V_wrapper. 我觉得中间步骤应该是完全多余的!此外,它使界面更难阅读。包装器的重点首先是对vec用户隐藏 的实现,现在有一个莫名其妙的(不知道源代码)对象P_wrapper,它只用于构造另一个对象......

我想避免这种情况,并且只有一个包装器。有什么办法可以去掉中间人,这样我就可以回到第一个更简单的实现V_wrapper

4

2 回答 2

1

不要无缘无故地使用大括号初始化器;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;
};
于 2013-07-24T12:04:13.247 回答
1

您需要删除默认的复制构造函数和赋值运算符。这些函数是隐式定义的,需要显式删除,因为它们会尝试复制向量及其内容(这是对 a 的非法操作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;
};
于 2015-01-31T01:14:07.120 回答