Ælex
Ælex

Reputation: 14869

C++11 copying std::vector of std::unique_ptr which is a member

I have a class graph which has a member:

std::vector<std::unique_ptr<layer>> _layers;

I understand that the nature of std::unique_ptr is to be non-copyable. My graph::graph(const graph & rhs); copy constructor produces a compilation error, because my ordinary implementation violates the nature of std::unique_ptr.

graph::graph(const graph & rhs)
: _layers(rhs._layers) {}

If I do a std::move then I will be violating the constness of param rhs, which is not what I want. I know I can make deep copies (e.g., create new unique pointers for each object stored in rhs._layers) but is there some elegant way of doing this, other than iterating each item in rhs._layers and allocating a new unique pointer?

gcc/g++ is c++11 not c++14

My current solution is deep copying the objects and allocating new pointers:

graph::graph(const graph & rhs)
{
   for (const auto & ptr : rhs._layers)
       _layers.emplace_back(std::unique_ptr<layer>(new layer(*ptr)));
}

Upvotes: 1

Views: 2298

Answers (3)

Brian Rodriguez
Brian Rodriguez

Reputation: 4376

The most elegant solution would use the STL:

graph::graph(const graph & rhs)
{
    _layers.reserve(rhs._layers.size());
    std::transform(
        std::begin(rhs._layers),
        std::end(rhs._layers),
        std::back_inserter(_layers),
        [](const std::unique_ptr<layer>& uptr) {
            return std::unique_ptr<layer>{uptr ? new layer{*uptr} : nullptr};
        });
}

std::transform, std::back_inserter

Upvotes: 7

Fozi
Fozi

Reputation: 5145

You can't make a copy but you can make a move constructor:

graph::graph(graph && rhs)

You should be able to move the _layers vector in there and then you should be able to move graph instances.

If this is not what you want then you will have to abandon the use of unique_ptr or add a layer of indirection to the _layers vector if that can be shared among graph instances.

Edit: An alternative solution would be to not use pointers in the vector at all but emplace the instances into the vector directly. This way the vector would be copied with all the contents naturally.

Upvotes: 0

M. Bogdanov
M. Bogdanov

Reputation: 86

You can also review the possibility to use the vector of std::shared_ptr instead of std::unique, in this case you can avoid real copying

Upvotes: 1

Related Questions