Malte
Malte

Reputation: 704

Initialization of vector<unique_ptr> fails with copy error

I'm struggeling to properly initialize a std::vector of std::unique_ptr's.

Example Code:

#include <iostream>
#include <vector>
#include <memory>

class Base{
    public:
        std::string getString() { return this->string; };
    protected:
        std::string string;
};
class Derived: public Base{
    public:
        Derived(std::string bla){
            this->string = bla;
    }
};
class Collection{
    protected:
        std::vector<std::unique_ptr<Base>> mappings;
};
class DerivedCollection: public Collection{
    public:
        DerivedCollection(std::string bla){
            std::vector<std::unique_ptr<Base>> maps;
            maps.push_back(std::make_unique<Derived>(bla));
            //or this: (does not work aswell)
            //maps.emplace_back(new Derived(bla));
            this->mappings = maps;
        }
};

int main(int argc, char** argv){
    DerivedCollection test = DerivedCollection("bla");
    return 0;
}

Somehow only defining mappings triggers the error:

/usr/include/c++/6.3.1/bits/stl_construct.h:75:7: 
error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Base; _Dp = std::default_delete<Base>]’
 { ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }

Which tells me that I somehow manage to construct a unique_ptr from a const unique_ptr, which does not work since unique_ptr is not copy-constructable.

Somehow this still fails even if I comment everything inside of the DerivedCollection constructor.

My guess is that I need a proper constructor for the Collection class. Im not sure howto define it though.

Any Ideas?

-- malte

Upvotes: 0

Views: 216

Answers (1)

Vittorio Romeo
Vittorio Romeo

Reputation: 93384

maps is non-copyable, as it's a vector of unique_ptr. Moving it into mappings solves the issue:

this->mappings = std::move(maps);

live wandbox example


Your code has other issues as well:

  • You should use the member initialization list to initialize data members instead of the constructor body.

  • getString could return const std::string& to avoid a copy.

  • Derived's constructor could std::move bla into the data member.

  • test could be initialized as follows: DerivedCollection test{"bla"}.

  • new should never be used - use make_unique instead.

Upvotes: 4

Related Questions