Search code examples
c++pointerstypesunique-ptr

C++ - Cast/Change-type of an unique_ptr


Edit: Thanks, amazing help, as always :)

I can't find the solution to this, I have an unique_ptr to a base class, that has the data of a derived class, and I want to set it's type to the derived class so I can access the derived members. See this code:

#include <memory>
#include <iostream>

class Base
{
public:
    int v1 = 0xAAAAAAAA;
};

class Derived : public Base
{
public:
    int v2 = 0xBBBBBBBB;
};

int main()
{

    std::unique_ptr<Base> b1(new Derived); //How to access b1->v2 ?
    std::unique_ptr<Base> b2(new Base);


    std::getchar(); 
    return 0;
}

The type of b1 is Base but it's data contains the data of Derived. See:

Screenshot of the problem. We can see data bytes corresponding to Derived

Is it hard to get ? I thought about manipulating memory bytes, like saying [b1+4] (pseudo thoughts) and accessing it, but I think about complicated objects, because I'm doing an entity system for a game, I can't do this :(

Thanks !


Solution

  • Your options are:

    1) Cast C-like pointer (recommended)

    std::unique_ptr<Base> b2(new Base);
    Derived * p = static_cast<Derived *>(b2.get());
    

    2) Implement your own static_unique_ptr_cast where you delete b1 and create a new std::unique_ptr:

    template<typename Derived, typename Base, typename Del>
    std::unique_ptr<Derived, Del> 
    static_unique_ptr_cast(std::unique_ptr<Base, Del> && p)
    {
        auto d = static_cast<Derived *>(p.release());
        return std::unique_ptr<Derived, Del>(d, std::move(p.get_deleter()));
    }
    

    The function takes rvalue reference to ensure you're not stealing the resource from lvalue. Usage:

    std::unique_ptr<Base> b1(new Derived);
    std::unique_ptr<Derived> p = static_unique_ptr_cast<Derived>(std::move(b1));
    

    Note: If you think you need to use 2) I would consider your design being flawed. The cast is not in the STL for some reason.

    Edit: The static_unique_ptr_cast now keeps the deleter.