shared_ptr and slicing

后端 未结 2 662
后悔当初
后悔当初 2021-01-11 22:01

Someone I worked with once said that shared_ptr was unsafe and would slice when casting from a derived class to a base class (i.e. upcasting). For example if there were 2 cl

相关标签:
2条回答
  • 2021-01-11 22:27

    That someone is wrong, object slicing doesn't apply to pointers. That the pointer usage is wrapped away in a shared_ptr doesn't change that - it doesn't do any particular magic here, it initializes an internal pointer with the value passed to its constructor.

    Simplified it could look e.g. like this for the purpose of this question:

    template<class T> struct ptr {
        T* t;
        ptr(T* t) : t(t) {}
        // ...
    };
    

    You lose the static type-information of B, yes, but nothing changes regarding the object pointed to.

    0 讨论(0)
  • 2021-01-11 22:31

    It is true that object slicing doesn't apply to pointers

    Pointers are PODs (just for the record: shared_ptrs aren't).

    The question quotes:

    shared_ptr can be implicitly converted to shared_ptr whenever T* can be implicitly converted to U*.

    This is about converting from one type to another, which is different from upcasting. There's no inheritance relationship between shared_ptr<A> and shared_ptr<B>, whether or not A derives from B or viceversa. This is the reason why the shared_ptr object itself doesn't slice.

    It is not true that object slicing cannot be a concern

    Consider a class hierarchy A, B with no virtual destructors.

    std::shared_ptr<A> a(new B);
    auto a = std::make_shared<B>();
    

    will capture B's deallocator and then will call B's destructor when needed

    std::shared_ptr<A> a((A*)(new B));
    

    will do no such thing and will cause slicing problems in the pointed-to object.

    It is not true that nothing is changed by the fact that the pointer usage is wrapped away in a smart pointer

    For example, using unique_ptr has different behaviour:

    std::unique_ptr<A> a(new B);
    std::unique_ptr<A> a((A*)(new B));
    

    will both exhibit slicing problems, while

    auto a = std::make_unique<B>();
    

    won't.

    Using a plain pointer doesn't help either:

    A* a = new B{};
    delete a;
    

    is a recipe for disaster.

    Example code available here.

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