Downcasting shared_ptr<Base> to shared_ptr?

前端 未结 3 1482
温柔的废话
温柔的废话 2020-11-30 20:28

Update: the shared_ptr in this example is like the one in Boost, but it doesn\'t support shared_polymorphic_downcast (or dynamic_pointer_cast or static_pointer_cas

相关标签:
3条回答
  • 2020-11-30 20:38

    I assume you're using boost::shared_ptr... I think you want dynamic_pointer_cast or shared_polymorphic_downcast.

    However, these require polymorphic types.

    what kind of type Base* const is? const Base* I understand, but Base* const? What does const refer to in this case?

    • const Base * is a mutable pointer to a constant Base.
    • Base const * is a mutable pointer to a constant Base.
    • Base * const is a constant pointer to a mutable Base.
    • Base const * const is a constant pointer to a constant Base.

    Here's a minimal example:

    struct Base { virtual ~Base() { } };   // dynamic casts require polymorphic types
    struct Derived : public Base { };
    
    boost::shared_ptr<Base> base(new Base());
    boost::shared_ptr<Derived> derived;
    derived = boost::static_pointer_cast<Derived>(base);
    derived = boost::dynamic_pointer_cast<Derived>(base);
    derived = boost::shared_polymorphic_downcast<Derived>(base);
    

    I'm not sure if it was intentional that your example creates an instance of the base type and casts it, but it serves to illustrate the difference nicely.

    The static_pointer_cast will "just do it". This will result in undefined behavior (a Derived* pointing at memory allocated for and initialized by Base) and will likely cause a crash, or worse. The reference count on base will be incremented.

    The dynamic_pointer_cast will result in a null pointer. The reference count on base will be unchanged.

    The shared_polymorphic_downcast will have the same result as a static cast, but will trigger an assertion, rather than seeming to succeed and leading to undefined behavior. The reference count on base will be incremented.

    See (dead link):

    Sometimes it is a little hard to decide whether to use static_cast or dynamic_cast, and you wish you could have a little bit of both worlds. It is well known that dynamic_cast has a runtime overhead, but it is safer, whereas static_cast has no overhead at all, but it may fail silently. How nice it would be if you could use shared_dynamic_cast in debug builds, and shared_static_cast in release builds. Well, such a thing is already available and is called shared_polymorphic_downcast.

    0 讨论(0)
  • 2020-11-30 20:46

    If somebody gets here with boost::shared_ptr...

    This is how you can downcast to the derived Boost shared_ptr. Assuming Derived inherits from Base.

    boost::shared_ptr<Base> bS;
    bS.reset(new Derived());
    
    boost::shared_ptr<Derived> dS = boost::dynamic_pointer_cast<Derived,Base>(bS);
    std::cout << "DerivedSPtr  is: " << std::boolalpha << (dS.get() != 0) << std::endl;
    

    Make sure 'Base' class/struct has at least one virtual function. A virtual destructor also works.

    0 讨论(0)
  • 2020-11-30 20:48

    You can use dynamic_pointer_cast. It is supported by std::shared_ptr.

    std::shared_ptr<Base> base (new Derived());
    std::shared_ptr<Derived> derived =
                   std::dynamic_pointer_cast<Derived> (base);
    

    Documentation: https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast

    Also, I don't recommend using cast operator in the base class. Implicit casting like this may become the source of bugs and errors.

    -Update: If the type is not polymorphic, std::static_pointer_cast may be used.

    0 讨论(0)
提交回复
热议问题