Both unique_ptr
and shared_ptr
accept a custom deleter to call on the object they own. But in the case of unique_ptr
, the deleter is passed as a template parameter of the class, whereas the type of shared_ptr
's custom deleter is to be specified as a template parameter of the constructor.
template <class T, class D = default_delete<T>> class unique_ptr { unique_ptr(T*, D&); //simplified ... };
and
template<class T> class shared_ptr { template<typename D> shared_ptr(T*, D); //simplified ... };
I can't see why such difference. What requires that?
In short: Use unique_ptr when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed. Use shared_ptr when you want multiple pointers to the same resource.
The uses of unique_ptr include providing exception safety for dynamically allocated memory, passing ownership of dynamically allocated memory to a function, and returning dynamically allocated memory from a function.
A unique_ptr does not share its pointer. It cannot be copied to another unique_ptr , passed by value to a function, or used in any C++ Standard Library algorithm that requires copies to be made. A unique_ptr can only be moved.
If you provide the deleter as template argument (as in unique_ptr
) it is part of the type and you don't need to store anything additional in the objects of this type. If deleter is passed as constructor's argument (as in shared_ptr
) you need to store it in the object. This is the cost of additional flexibility, since you can use different deleters for the objects of the same type.
I guess this is the reason: unique_ptr
is supposed to be very lightweight object with zero overhead. Storing deleters with each unique_ptr
could double their size. Because of that people would use good old raw pointers instead, which would be wrong.
On the other hand, shared_ptr
is not that lightweight, since it needs to store reference count, so storing a custom deleter too looks like good trade off.
Shared pointers of different types can share the ownership of the same object. See overload (8) of std::shared_ptr::shared_ptr
. Unique pointers don't need such a mechanism, as they don't share.
template< class Y > shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;
If you didn't type-erase the deleter, you wouldn't be able to use such a shared_ptr<T, Y_Deleter>
as a shared_ptr<T>
, which would make it basically useless.
Why would you want such an overload?
Consider
struct Member {}; struct Container { Member member };
If you want to keep the Container
alive, while you use the Member
, you can do
std::shared_ptr<Container> pContainer = /* something */ std::shared_ptr<Member> pMember(pContainer, &pContainer->member);
and only have to hold onto pMember
(perhaps put it into a std::vector<std::shared_ptr<Member>>
)
Or alternatively, using overload (9)
template< class Y > shared_ptr( const shared_ptr<Y>& r ) noexcept; // Only exists if Y* is implicitly convertible to T*
You can have polymorphic sharing
struct Base {}; struct Derived : Base {}; void operate_on_base(std::shared_ptr<Base>); std::shared_ptr<Derived> pDerived = /* something*/ operate_on_base(pDerived);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With