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 toshared_ptr<U>
wheneverT*
can be implicitly converted toU*
.
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.
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.
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.
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.