Search code examples
c++c++11castingshared-ptrunique-ptr

Alternatives of static_pointer_cast for unique_ptr


I understand that using static_pointer_cast with unique_ptr would lead to a shared ownership of the contained data.
In other terms, what I'd like to do is:

unique_ptr<Base> foo = fooFactory();
// do something for a while
unique_ptr<Derived> bar = static_unique_pointer_cast<Derived>(foo);

Anyway doing that results with two unique_ptr that should never exist at the same time, so it is simply forbidden.
Right, it makes sense, absolutely, that's why there doesn't exist anything like static_unique_pointer_cast indeed.

So far, in cases where I want to store pointers to those base classes, but I also need to cast them to some derived classes (as an example, imagine a scenario involving type erasure), I've used shared_ptrs because of what I've above mentioned.

Anyway, I was guessing if there are alternatives to shared_ptrs for such a problem or if they are really the best solution in that case.


Solution

  • #Raw pointers

    The solution for your problem is to get the raw (non-owning) pointer and cast it - then just let the raw pointer go out of scope and let the remaining unique_ptr<Base> control the lifetime of the owned object.

    Like this:

    unique_ptr<Base> foo = fooFactory();
    
    {
        Base* tempBase = foo.get();
        Derived* tempDerived = static_cast<Derived*>(tempBase);
    } // tempBase and tempDerived go out of scope here, but foo remains -> no need to delete
    

    #Unique_pointer_cast The other option is to use the release() function of unique_ptr to wrap it into another unique_ptr.

    Like this:

    template<typename TO, typename FROM>
    unique_ptr<TO> static_unique_pointer_cast (unique_ptr<FROM>&& old){
        return unique_ptr<TO>{static_cast<TO*>(old.release())};
        // conversion: unique_ptr<FROM>->FROM*->TO*->unique_ptr<TO>
    }
    
    unique_ptr<Base> foo = fooFactory();
    
    unique_ptr<Derived> foo2 = static_unique_pointer_cast<Derived>(std::move(foo));
    

    Remember that this invalidates the old pointer foo

    #Reference from raw pointers Just for completeness of the answer, this solution was actually proposed as a small modification of the raw pointers by the OP in the comments.

    Similar to using raw pointers one can cast the raw pointers and then create a reference out of them by derefering. In this case it is important to guarantee that the lifetime of the created reference does not exceed the lifetime of the unique_ptr.

    Sample:

    unique_ptr<Base> foo = fooFactory();
    Derived& bar = *(static_cast<Derived*>(foo.get()));
    // do not use bar after foo goes out of scope