2

When a class has a unique_ptr of a Base class what is a good way to implement the copy constructor.

Let me try to explain it with an example:

struct Base
{
    virtual void doSth() = 0; // to make the class abstract.
};

struct Derived : public Base
{
    virtual void doSth() override {}
};

struct Foo
{
    std::unique_ptr<Base> bar;

    Foo(const Foo& other) : bar(new Base(*other.bar))   // cant do it, its abstract.
    {
        bar = std::move(other.bar); // cant do it, reference object is modified.
    }
};

Here as the class is abstract i cannot use its copy constructor. and also cannot use move on a constant reference ( we shouldnt do it actually, do not modify the object).

What I end up with is like so:

struct Base
{
    virtual void doSth() = 0; // to make the class abstract.
};

struct Derived : public Base
{
    virtual void doSth() override {}

    Derived(const Base* b)
    {

    }
};

struct Foo
{
    std::unique_ptr<Base> bar;

    Foo(const Foo& other) : bar(new Derived(other.bar.get()))
    {

    }
};

However, it does not feel quite right, does it?

bahti
  • 636
  • 1
  • 7
  • 21
  • @40two Actually, i have seen the question you referenced before. But, maybe I could not put it clearly. My concern is about unique_ptrs of abstract Base classes and how to handle them in copy constructors. – bahti May 18 '14 at 02:33
  • Thanks for the point, you are right I'm removing my comment. – 101010 May 18 '14 at 02:35
  • Take a look at [this question](http://stackoverflow.com/questions/12255546/c-deep-copying-a-base-class-pointer) for how to deep copy an object using only the base class pointer. – merlin2011 May 18 '14 at 02:44
  • If you want to copy the pointed-to object, the standard way is via a virtual `clone()` method. – n. m. could be an AI May 18 '14 at 02:46

2 Answers2

2

If you need to copy polymorphically, you will need to provide that in the interface of the type you are holding. Add a clone virtual function to Base and use that to create a copy that you can store in the copied Foo.

Other alternatives include not copying (delete the copy constructor) or use reference semantics (copies refer to the same object: change unique_ptr for shared_ptr) but neither of those alternatives really provide copies.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
2

Here is the code for David's answer. Note that the virtual clone() is described in this answer.

#include <stdlib.h>
#include <cstddef>
#include <memory>


struct Base
{
   virtual void doSth() = 0; // to make the class abstract.
   virtual Base* clone() const = 0;
};

struct Derived : public Base
{
    virtual void doSth() override {}
    virtual Derived* clone() const {
        return new Derived(*this);
    }
};

struct Foo
{
    std::unique_ptr<Base> bar;

    Foo(const Foo& other) : bar(other.bar->clone())   // cant do it, its abstract.
    {

    }
};
Community
  • 1
  • 1
merlin2011
  • 71,677
  • 44
  • 195
  • 329