【问题标题】:Deleter type in unique_ptr vs. shared_ptr [duplicate]unique_ptr 与 shared_ptr 中的删除器类型 [重复]
【发布时间】:2017-05-19 15:29:57
【问题描述】:

当我发现标准以两种完全不同的方式定义指针可能拥有的 Deleter 时,我觉得这非常奇怪。这是来自cppreference::unique_ptrcppreference::shared_ptr 的声明:

template<
    class T,
    class Deleter = std::default_delete<T>
> class unique_ptr;

template< class T > class shared_ptr;

如您所见,unique_ptr 将 Deleter 对象的类型“保存”为模板参数。这也可以从稍后从指针中检索 Deleter 的方式中看出:

// unique_ptr has a member function to retrieve the Deleter
template<
    class T,
    class Deleter = std::default_delete<T>
>
Deleter& unique_ptr<T, Deleter>::get_deleter();

// For shared_ptr this is not a member function
template<class Deleter, class T>
Deleter* get_deleter(const std::shared_ptr<T>& p);

有人可以解释这种差异背后的原因吗?我显然赞成unique_ptr 的概念,为什么这也不适用于shared_ptr?另外,为什么get_deleter 在后一种情况下是非成员函数?

【问题讨论】:

  • 有人将不得不挖掘原始提案,但我有根据的猜测:没有删除器作为模板参数使shared_ptr 更易于使用,但您需要支付类型擦除成本。将get_deleter 设为成员将使编写带有shared_ptr&lt;T&gt; 的通用代码更加乏味——您需要编写sp.template get_deleter&lt;Deleter&gt;() 而不是get_deleter&lt;Deleter&gt;(sp)。这就是为什么std::get 不是会员。
  • 稍微扩展 @T.C.说,unique_ptr 的设计目标之一是它应该(非常接近)零开销。擦除删除器的类型很方便,但会引入擦除带来的运行时间开销,因此与 shared_ptr 相比,unique_ptr 不太适合
  • 您还应该注意,由于这种差异,即使Base 没有虚拟析构函数,shared_ptr&lt;Base&gt; p = make_shared&lt;Derived&gt;() 也会做正确的事情。 proof.

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


【解决方案1】:

在这里您可以找到智能指针的原始提案:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html

它非常准确地回答了你的问题:

由于删除器不是类型的一部分,因此更改分配策略不会破坏源代码或二进制兼容性,并且不需要客户端重新编译。

这也很有用,因为给std::shared_ptr 的客户端一些更大的灵活性,例如shared_ptr 具有不同删除器的实例可以存储在同一个容器中。

另外,因为shared_ptr 实现无论如何都需要一个共享内存块(用于存储引用计数)并且因为与原始指针相比已经有一些开销,所以添加一个类型擦除删除器并不是什么大问题在这里交易。

另一方面,unique_ptr 完全没有开销,每个实例都必须嵌入其删除器,因此将其作为类型的一部分是很自然的事情。

【讨论】:

  • 类型擦除删除器如何被称为 btw?
  • @WorldSEnder:这取决于实现,但通常的方法是将具体的删除器封装到一个模板类中,该类实现(继承)用于删除 T* 的接口。所以当引用计数达到零时,实现调用虚方法,这个调用被分派给嵌入类,嵌入类又调用具体的删除器。它与 std::function 的机制相同。
  • 请注意,std::function 和可能 shared_ptr 的“原始”较低级别的实现在实践中将比基于 vtable 的更快,但很少有标准库使用它们(请参阅“最快的委托”通过谷歌)。 vtable 实现是最容易理解的,因为它看起来像普通的 C++。
猜你喜欢
  • 2016-01-03
  • 1970-01-01
  • 2015-02-04
  • 1970-01-01
  • 2016-09-18
  • 1970-01-01
  • 2020-04-10
  • 2015-09-11
相关资源
最近更新 更多