unique_ptr
和shared_ptr
都接受自定义析构函数来调用他们拥有的对象。但是在unique_ptr
的情况下,析构函数作为类的模板参数传递,而shared_ptr
的自定义析构函数的类型将被指定为模板构造函数的参数。
template <class T, class D = default_delete<T>>
class unique_ptr
{
unique_ptr(T*, D&); //simplified
...
};
和
template<class T>
class shared_ptr
{
template<typename D>
shared_ptr(T*, D); //simplified
...
};
我看不出为什么会有这样的差异。需要什么?
答案 0 :(得分:56)
如果您将删除器作为模板参数提供(如在unique_ptr
中),则它是该类型的一部分,您不需要在此类型的对象中存储任何其他内容。
如果将deleteter作为构造函数的参数传递(如在shared_ptr
中),则需要将其存储在对象中。这是额外灵活性的代价,因为您可以为相同类型的对象使用不同的删除器。
我想这就是原因:unique_ptr
应该是非常轻量级的对象,零开销。每个unique_ptr
存储删除者的数量可能会翻倍。因为人们会使用旧的原始指针代替,这是错误的。
另一方面,shared_ptr
不是那么轻量级,因为它需要存储引用计数,因此存储自定义删除器看起来也是很好的权衡。
答案 1 :(得分:1)
不同类型的共享指针可以共享同一对象的所有权。请参阅std::shared_ptr::shared_ptr
的{{3}}。唯一指针不需要这样的机制,因为它们不共享。
template< class Y >
shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;
如果您没有对删除器进行类型删除,则无法将shared_ptr<T, Y_Deleter>
用作shared_ptr<T>
,这会使其基本无效。
你为什么要这么过载?
考虑
struct Member {};
struct Container { Member member };
如果你想保持Container
活着,当你使用Member
时,你可以做到
std::shared_ptr<Container> pContainer = /* something */
std::shared_ptr<Member> pMember(pContainer, &pContainer->member);
并且只需抓住pMember
(可能将其放入std::vector<std::shared_ptr<Member>>
)
或者,使用overload(9)
template< class Y >
shared_ptr( const shared_ptr<Y>& r ) noexcept;
// Only exists if Y* is implicitly convertible to T*
您可以进行多态共享
struct Base {};
struct Derived : Base {};
void operate_on_base(std::shared_ptr<Base>);
std::shared_ptr<Derived> pDerived = /* something*/
operate_on_base(pDerived);