【问题标题】:Smart way to construct class member std::vector<std::unique_ptr<AClass> >构造类成员 std::vector<std::unique_ptr<AClass>> 的聪明方法
【发布时间】:2025-11-24 11:50:02
【问题描述】:

这个问题结合了unique_ptr as class member and move semantics fail to compile with clangC++ 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&lt;AClass&gt;设计一个中间包装器,如下

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

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

【问题讨论】:

  • 我知道这个问题真的很老,但我也遇到了同样的问题,只是想通了!

标签: c++ constructor wrapper stdvector unique-ptr


【解决方案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;
};

【讨论】:

  • utility 库在这个例子中做了什么?
  • 我仍然得到/usr/bin/../lib/c++/v1/memory:1681:31: error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr&lt;A, std::__1::default_delete&lt;A&gt; &gt;' errors from my compiler. The only difference with what you're doing is that my equivalent of you bar, called A` 是派生的;它的唯一成员是一个虚函数。这是编译器问题吗?
  • @Karrek SB 还有,我的_v 版本声明为public;不知道这算不算问题,我想我应该提一下……
  • 很可能是编译器问题。这应该有效。在最近的编译器上试用 (e.g. here)。
  • 我担心你会这么说。我在 Mac 上工作,在编译器和 C++11 语法方面遇到问题,尤其是在库链接方面。 clang 已经为我解决了大部分问题,除了我现在在这里展示的那个,而且我拥有除了最新版本的编译器之外的所有内容......这不仅仅是不方便。你在工作或有过使用 osx 的经验吗?我应该问'clang'的人吗?
【解决方案2】:

您需要删除默认的复制构造函数和赋值运算符。这些函数是隐式定义的,需要显式删除,因为它们会尝试复制向量及其内容(这是对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;
};

【讨论】:

    最近更新 更多