7

I have a std::unique_ptr<Derived> that I want to add to a std::vector<std::unique_ptr<Base>>.

std::unique_ptr<Derived> derivedObject;
std::vector<std::unique_ptr<Base>> vec;

vec.push_back(derivedObject) // Invalid arguments
mrkotfw
  • 59
  • 7
  • 1
    Possible duplicate of [unique\_ptr to a base class](http://stackoverflow.com/questions/17473900/unique-ptr-to-a-base-class) – freakish Nov 09 '16 at 15:38

3 Answers3

9

unique_ptr guarantees that it's only one pointer that points to the memory, so you can't just copy it to the vector, you need to move it:

vec.push_back(std::move(derivedObject));

If you look at the unique_ptr constructors (http://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr) you see, that this class doesn't implement the copy constructor, but implements move constructor (http://en.cppreference.com/w/cpp/language/move_constructor).

Marcin Kolny
  • 633
  • 7
  • 14
5

This is because you cannot copy a std::unique_ptr. The problem is solvable using std::move():

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

struct Base {
};

struct Derived : public Base {
};

int main()
{
    std::unique_ptr<Derived> derivedObject;
    std::vector<std::unique_ptr<Base>> vec;

    vec.push_back(std::move(derivedObject));    
               // ^^^^^^^^^^             ^
}

Here's a live demo.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
3

cppreference about unique_ptr

If T is a derived class of some base B, then std::unique_ptr < T > is implicitly convertible to std::unique_ptr < B >.

So, the problem is not of conversion failure.

The class satisfies the requirements of MoveConstructible and MoveAssignable, but not the requirements of either CopyConstructible or CopyAssignable.

This is what causes the failure. unique_ptr can be moved but can't be copied, as that would break the single-ownership agreement.


So either use std::move, or use make_derived directly:

vec.push_back(std::move(derivedObject));  //Option 1. When unique_ptr is already created.
OR,
vec.push_back(make_unique<Derived>());    //Option 2. New unique_ptr

Using option #2, you can avoid having a local variable for no purpose. Anyway upon performing move on unique_ptr, the object owned by the unique_ptr is disposed. Demo.

Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79