Smart way to construct class member std::vector<std::unique_ptr<AClass> >

我与影子孤独终老i 提交于 2019-12-23 02:03:52

问题


This question combines unique_ptr as class member and move semantics fail to compile with clang and C++ std::vector in constructor.

My goal is to construct a wrapper

struct V_wrapper{
       std::vector<std::unique_ptr<AClass> > vec;
       V_wrapper(std::vector<std::unique_ptr<AClass> > v) : vec{std::move(v)} {}
};

Unfortunately this code does not compile, because the compiler (clang Apple LLVM version 4.2) attempts to copy construct the vector v which is not supported. On the other hand, if I design an intermediate wrapper for std::unique_ptr<AClass>, as follows

struct P_wrapper{
       std::unique_ptr<AClass> Ptr;
       P_wrapper(std::unique_ptr<AClass>& p) : Ptr(std::move(p)) {}
};

and write V_wrapper as follows

struct V_wrapper{
       std::vector<P_wrapper > vec;
       V_wrapper(std::vector<P_wrapper > v) : vec{std::move(v)} {}
};

then I have no problems. I think (emphasis) that the reason this works is that the constructor of the vector realizes that you should use the reference to move rather than trying to copy, just as in unique_ptr as class member and move semantics fail to compile with clang.

Unfortunately, this leads to the rather inconvenient construction procedure that I make the std::vector<std::unique_ptr<AClass> >, use it to construct the P_wrapper, and finally use that to construct the V_wrapper. I feel that the middle step should be totally redundant! In addition, it makes the interface much harder to read. The whole point of the wrapper in the first place was to hide the implementation of vec from the user, and now there's an inexplicable (not knowing the source code) object P_wrapper that's only used to construct another object....

I want to avoid this, and only have one wrapper. Is there any way of cutting out the middle man so I can go back to the first, much simpler implementation of V_wrapper?


回答1:


Don't use brace initalizers gratuitously; std::vector has a constructor that consumes initializer lists. The obvious way to write this compiles fine for me:

#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;
};



回答2:


You need to delete the default copy constructor and assignment operators. These functions are defined implicitly, and need to be explicitly deleted, as they will attempt to copy the vector and its contents (which is an illegal operation on 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;
};


来源:https://stackoverflow.com/questions/17833238/smart-way-to-construct-class-member-stdvectorstdunique-ptraclass

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!