【问题标题】:Why does unique_ptr have the deleter as a type parameter while shared_ptr doesn't?为什么 unique_ptr 将删除器作为类型参数而 shared_ptr 没有?
【发布时间】:2011-07-26 11:51:14
【问题描述】:

std::unique_ptr 模板有两个参数:指针类型和删除器类型。第二个参数有一个默认值,所以你通常只写std::unique_ptr<int>之类的东西。

std::shared_ptr 模板只有一个参数:指针的类型。但是您也可以使用自定义删除器,即使删除器类型不在类模板中。通常的实现使用类型擦除技术来做到这一点。

std::unique_ptr 没有使用相同的想法是否有原因?

【问题讨论】:

    标签: c++ smart-pointers type-erasure


    【解决方案1】:

    部分原因是shared_ptr 无论如何都需要一个显式控制块来控制引用计数,并且在顶部插入一个删除器并不是什么大问题。 unique_ptr 但是不需要任何额外的开销,添加它是不受欢迎的——它应该是一个零开销的类。 unique_ptr 应该是静态的。

    如果您想要这种行为,您可以随时在顶部添加自己的类型擦除 - 例如,您可以使用 unique_ptr<T, std::function<void(T*)>>,这是我过去做过的事情。

    【讨论】:

    • +1。类型擦除不是一件“好事”,它更像是一种必要的邪恶。如果您可以使用更简单的解决方案,那么您应该这样做。 unique_ptr 是一个比shared_ptr 更简单、更轻量级的智能指针。
    • @DeadMG:我没有得到“unique_ptr 应该是静态的”部分。这是什么意思——特别是“静态”的用法?
    • @Jon:这意味着它不应该解析动态使用的功能——编译器应该静态解析所有涉及的调用。这使它能够与您妈妈最好的自制 C 代码 w.r.t 竞争。各方面的表现。
    • @DeadMG:因此,在这种情况下,“静态”是“零开销”的较弱版本(我将其解读为“静态且没有更大的内存占用”)。解决了,谢谢。
    • 难道不能两全其美吗?对于某些删除器类型(包括默认),删除器只有一个可能的 ,因此没有内存开销。但是,对于某些删除器类型,unique_ptr 将扩展为包含删除器的值。我想这可能很复杂,并且可能需要对类进行不同的设计。
    【解决方案2】:

    除了 DeadMG 指出的原因之外,另一个原因是可以编写

    std::unique_ptr<int[]> a(new int[100]);
    

    ~unique_ptr 将调用delete正确 版本(通过default_delete&lt;_Tp[]&gt;),这要归功于TT[] 的专门化。

    【讨论】:

    • 我看不出有多大的变化。您可以在没有 deleter 参数的情况下专门针对 T[]
    • 是的,这是可能的,但不太优雅和不太灵活,因为它会被硬编码在 unique_ptr 中,而不是删除器。请注意,您可以插入foo_delete,它也可以做一些完全不同的事情。例如,拥有一个手动运行析构函数然后标记对象以供 GC 稍后回收的删除器将是一件有趣的事情。智能指针根本不需要知道。
    • 就像 shared_ptr 不需要知道一样。当专门针对 T[] 时,您可以使用相同类型的擦除技巧,不是吗?
    • 不确定...也许,也许不是。使用shared_ptr 的同一行代码编译失败,这表明shared_ptr 显然没有 专门化。假设标准库编写者不随机包含/排除很容易在你今天感觉如何的基础上合并的关键功能,似乎必须有一个相当大的、非- 某处明显的障碍。
    • @Damon: T[] 专业化根本不是关键功能。我什至不知道为什么它在unique_ptr。为此,我们已经有std::vector&lt;T&gt;
    【解决方案3】:

    来自 C++ Primer(第 5 版),第 16.1.6 章 - 效率和灵活性

    shared_ptr 和 unique_ptr 的明显区别在于它们的策略 用于管理他们持有的指针——一个类给我们共享所有权; 另一个拥有它持有的指针。这种差异对于 这些类的作用。

    这些类在允许用户覆盖其默认值的方式上也有所不同 删除器。我们可以通过传递一个来轻松地覆盖 shared_ptr 的删除器 创建或重置指针时的可调用对象。相比之下,类型 删除器是 unique_ptr 对象类型的一部分。用户必须提供 当他们定义 unique_ptr 时,该类型作为显式模板参数。作为 因此,unique_ptr 的用户提供自己的 删除器。

    通过在编译时绑定删除器,unique_ptr 避免了运行时开销 间接调用它的删除器。通过在运行时绑定删除器, shared_ptr 让用户更容易覆盖删除器。

    【讨论】:

      猜你喜欢
      • 2014-05-28
      • 2018-10-16
      • 1970-01-01
      • 2017-05-19
      • 2020-04-10
      • 1970-01-01
      • 2015-07-23
      • 1970-01-01
      相关资源
      最近更新 更多