简体   繁体   中英

shared_ptr and slicing

Someone I worked with once said that shared_ptr was unsafe and would slice when casting from a derived class to a base class (ie upcasting). For example if there were 2 classes A and B where B derived from A, then

shared_ptr<A> a(new B)

would slice. I pointed him to http://www.boost.org/doc/libs/1_43_0/libs/smart_ptr/shared_ptr.htm where it says

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

implied that it's safe to use in those contexts but he didn't seem to think so.

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 eg 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.

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

Pointers are PODs (just for the record: shared_ptr s 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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM