为什么unique_ptr在shared_ptr只占用一个时需要两个模板参数?

时间:2014-01-25 19:15:07

标签: c++ c++11 std shared-ptr unique-ptr

unique_ptrshared_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
    ...
};

我看不出为什么会有这样的差异。需要什么?

2 个答案:

答案 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);