Drew
Drew

Reputation: 13398

How do I construct an object that has a unique_ptr member?

I have a base class:

class Base {
public:
    Base(??? new_p) : p(new_p) {} 
    std::unique_ptr<MyType> p;
}

And a derived class:

class Derived : public Base {
    Derived(??? new_p) : Base(new_p) {}
}

What type do I replace the question marks with if I want to construct Derived? Other changed are also fine. I want to make sure Derived can be constructed without copying the MyType that is pointed to by p.

Upvotes: 3

Views: 285

Answers (3)

Tony Delroy
Tony Delroy

Reputation: 106096

Depends what you want to support - either or both of the constructors below make sense, from MyType* or a std::unique_ptr<MyType>&&, which requires a movable unique_ptr be supplied by the caller. Simply using std::unique_ptr<MyType> works too, because std::unique_ptr has a constructor from other movable instances... just a matter of taste whether you want to emphasise the necessarily-transient nature of the caller's incoming unique_ptr in your own code.

class Base
{
  public:
    Base(MyType* new_p) : p(new_p) { } 
    Base(std::unique_ptr<MyType>&& new_p) : p(std::move(new_p)) { } 

    std::unique_ptr<MyType> p;
};

class Derived : public Base
{
  public:
    Derived(MyType* new_p) : Base(new_p) { }
    Derived(std::unique_ptr<MyType>&& new_p) : Base(std::move(new_p)) { }
};

See it running here

Upvotes: 1

Jose Palma
Jose Palma

Reputation: 756

This worked for me. Edit to note I'm using string as the type only to make it easier to read, you must replace it with your type.

#include <memory>
#include <string>
#include <iostream>
#include <utility>

class Base {
public:
    Base(std::unique_ptr<std::string> new_p) 
      : p(std::move(new_p)) {} 
    std::unique_ptr<std::string> p;
};

class Derived : public Base {
public:
    Derived(std::unique_ptr<std::string> new_p) 
      : Base(std::move(new_p)) {}
};

int main(){
    std::unique_ptr<std::string> text(new std::string("Hello world"));

    Derived a(std::move(text));

    std::cout << *(a.p);
}

Upvotes: 0

Praetorian
Praetorian

Reputation: 109119

I'd replace ??? with std::unique_ptr<MyType> and then std::move it in the mem-initializer.

class Base {
public:
    Base(std::unique_ptr<MyType> new_p) : p(std::move(new_p)) {} 
    std::unique_ptr<MyType> p;
};

class Derived : public Base {
    Derived(std::unique_ptr<MyType> new_p) : Base(std::move(new_p)) {}
};

You could also use std::unique_ptr<MyType>&& instead of std::unique_ptr<MyType> and avoid the std::moves but I prefer the by-value approach for the reasons listed in this answer.

I would recommend against taking a MyType * argument. The problem with that solution is that it doesn't convey to the user your intent of taking ownership of the pointer passed to the constructor.

Upvotes: 1

Related Questions