'error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<A, std::__1::default_delete<A> >'

I'm constructing an object that takes a std::vector<std::unique_ptr<A> > as an argument. The constructor is defined like this

class B {
    std::vector <std::unique_ptr<A> > e_;

public:
    B(std::vector <std::unique_ptr<A> > e) : e_(std::move(e)){}

};

and then used as

std::vector <std::unique_ptr<A> > e;
B b(e);

and Xcode presents the error

error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr<A, std::__1::default_delete<A> >'
:new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
                 ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~`

Why is the error still persisting even though i am using std::move()?

EDIT: the error seems to vanish if i use B b(std::move(e)) instead of B b(e)), is there any way to move the move logic to the implementation of the function?



Solution 1:[1]

Your constructor argument is pass by value which will make a copy, but you cannot copy a std::unique_ptr. Passing by reference should work:

class B {
    std::vector <std::unique_ptr<float> > e_;

public:
    B(std::vector <std::unique_ptr<float> >& e) : e_(std::move(e)){}

};

But...I agree with the other comments that this is bad design. If you want B to own e but also want to manipulate e outside of B then it should be a public member, no fancy constructor needed:

class B {
public:
    std::vector <std::unique_ptr<float> > e_;
};

Solution 2:[2]

The problem, as the previous answers suggest, is that you cannot copy a std::unique_ptr. Passing the constructor argument by value will trigger a copy. That being said, if the intention is for B to own the unique_ptr, then the correct approach is to use B b(std::move(e)).

This is the design recommended by Herb Sutter: https://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/. Passing a unique_ptr by value makes it clear that the constructor takes ownership of the object away from the caller. Furthermore, because the compiler requires an explicit std::move, the semantics are clearly documented in code. That is, it is clear to users that the unique_ptr is invalidated by the constructor call because of the explicit std::move.

Solution 3:[3]

Why is the error still persisting even though i am using std::move()?

Because you are moving argument of ctor of B into member, which does not mean that variable e should or could be moved.

is there any way to move the move logic to the implementation of the function?

Even if it is possible, you should not do it. It should be clear for reader of code where e is used, that it was moved and cannot be used anymore.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Slava