unique_ptr and polymorphism

c++, c++11, smart-pointers

Solution

Initially I decided to simply change the definition of Push to use unique_ptrs too, but this generates compile errors when trying to use derived types.

You likely did not correctly deal with uniqueness.

void push(std::unique_ptr<int>);
int main() {
    std::unique_ptr<int> i;
    push(i); // Illegal: tries to copy i.
}

If this compiled, it would trivially break the invariant of `unique_ptr`, that only one `unique_ptr` owns an object, because both `i` and the local argument in `push` would own that `int`, so it is illegal. `unique_ptr` is move only, it's not copyable. It has nothing to do with derived to base conversion, which `unique_ptr` handles completely correctly.

If `push` owns the object, then use `std::move` to move it there. If it doesn't, then use a raw pointer or reference, because that's what you use for a non-owning alias.

Problem

I have some code that currently uses raw pointers, and I want to change to smart pointers. This helps cleanup the code in various ways. Anyway, I have factory methods that return objects and its the caller's responsibility to manager them. Ownership isn't shared and so I figure `unique_ptr` would be suitable. The objects I return generally all derive from a single base class, `Object`. For example, ``` class Object { ... }; class Number : public Object { ... }; class String : public Object { ... }; std::unique_ptr<Number> State::NewNumber(double value) { return std::unique_ptr<Number>(new Number(this, value)); } std::unique_ptr<String> State::NewString(const char* value) { return std::unique_ptr<String>(new String(this, value)); } ``` The objects returned quite often need to be passed to another function, which operates on objects of type `Object` (the base class). Without any smart pointers the code is like this. ``` void Push(const Object* object) { ... } // push simply pushes the value contained by object onto a stack, which makes a copy of the value Number* number = NewNumber(5); Push(number); ``` When converting this code to use `unique_ptrs` I've run into issues with polymorphism. Initially I decided to simply change the definition of `Push` to use `unique_ptrs` too, but this generates compile errors when trying to use derived types. I could allocate objects as the base type, like ``` std::unique_ptr<Object> number = NewNumber(5); ``` and pass those to `Push` - which of course works. However I often need to call methods on the derived type. In the end I decided to make `Push` operate on a pointer to the object stored by the `unique_ptr`. ``` void Push(const Object* object) { ... } std::unique_ptr<Object> number = NewNumber(5); Push(number.get()); ``` Now, to the reason for posting. I'm wanting to know if this is the normal way to solve the problem I had? Is it better to have `Push` operate on the `unique_ptr` vs the object itself? If so how does one solve the polymorphism issues? I would assume that simply casting the ptrs wouldn't work. Is it common to need to get the underlying pointer from a smart pointer? Thanks, sorry if the question isn't clear (just let me know). edit: I think my Push function was a bit ambiguous. It makes a copy of the underlying value and doesn't actually modify, nor store, the input object.

Original source