【问题标题】:Shouldn't `std::shared_ptr` use `std::default_delete` by default?`std::shared_ptr` 不应该默认使用 `std::default_delete` 吗?
【发布时间】:2018-07-10 00:12:21
【问题描述】:

std::default_deletecan be specialized 允许std::unique_ptrs 到painlessly manage types which have to be destroyed by calling some custom destroy-function instead of using delete p;

在 C++ 中,基本上有两种方法可以确保对象由 std::shared_ptr 管理:

  1. 使用std::make_sharedstd::allocate_shared 创建由共享指针管理的它。这是首选方式,因为它将所需的两个内存块(有效负载和引用计数)合并为一个。虽然只剩下std::weak_ptrs,但对引用计数的需求仍然必然会限制有效负载的内存。

  2. 之后使用a constructor.reset() 将管理分配给共享指针。

第二种情况,当不提供自定义删除器时很有趣:

具体来说,它被定义为使用自己的未指定类型的删除器,分别使用delete [] p;delete p;,这取决于是否为数组实例化std::shared_ptr

引自 n4659 (~C++17):

template<class Y> explicit shared_ptr(Y* p);

4 要求:Y 应为完整类型。表达式delete[] p,当T 是数组类型时,或delete p,当T 不是数组类型时,应具有良好定义的行为,并且不应抛出异常。
5 效果:当T不是Array类型时,构造一个拥有指针pshared_ptr对象。否则,构造一个拥有pshared_ptr 和一个调用delete[] p 的未指定类型的删除器。当T 不是数组类型时,启用shared_from_thisp。如果抛出异常,当T不是数组类型时调用delete p,否则调用delete[] p
6 后置条件:use_count() == 1 &amp;&amp; get() == p.
[…]

template<class Y> void reset(Y* p);

3 效果:相当于shared_ptr(p).swap(*this)

我的问题是:

  1. 是否有一个最好的理由没有指定使用std::default_delete 来代替?
  2. 任何有效的(并且可能有用的?)代码会被该更改破坏吗?
  3. 是否已有建议这样做?

【问题讨论】:

  • 嗯,你的专业必须“满足原始模板的标准库要求”,部分要求是它调用delete(或delete[])。我不明白您如何合法地将其专门用于做其他事情。
  • 当使用与实例相同的内存块创建控制块时,默认删除是否仍然有效。 (弱指针需要不同的破坏时刻)
  • @T.C.特化以唯一正确的方式删除对象。基本模板可能是错误的,所以没问题。
  • @JVApen:如果std::make_sharedstd::allocate_shared 合并两个分配,则不使用单独的删除器。这只是问题的背景。

标签: c++ default shared-ptr delete-operator c++20


【解决方案1】:

是否有一个最好的理由没有指定使用std::default_delete 来代替?

因为它不会做你想做的事。看,仅仅因为你可以专攻某事并不意味着你可以劫持它。标准说([namespace.std]):

只有当声明依赖于用户定义的类型并且特化满足原始模板的标准库要求并且没有明确禁止时,程序才能将任何标准库模板的模板特化添加到命名空间 std。

std::default_delete&lt;T&gt;::operator()(T* ptr) 行为的标准库要求是它“在 ptr 上调用 delete”。所以你对它的专业化必须做同样的事情。

因此,让shared_ptr 执行delete ptr; 和让shared_ptr 调用default_delete&lt;T&gt;{}(ptr) 之间应该没有区别。

这就是为什么unique_ptr 采用删除器类型,而不是依靠您对其进行专门化。


来自cmets:

特化以唯一正确的方式删除对象。

但这不是要求所说的。它显示“在ptr 上致电delete。”它并没有说诸如“结束ptr 指向的对象的生命周期”或“销毁ptr 引用的对象”之类的更模棱两可的内容。它给出了必须发生的明确代码。

你的专业必须坚持下去。

如果你仍然不相信,论文P0722R1 是这样说的:

请注意,该标准要求 default_delete&lt;T&gt; 的特化与调用 delete p; 具有相同的效果,

很明显,作者同意专门化default_delete 并不是一种添加自己行为的机制。

所以你的问题的前提是无效的。


但是,让我们假设您的问题是有效的,这样的专业化会起作用。有效与否,专门 default_delete 来自定义删除器行为并不是这样做的预期方法。如果这是意图,则您根本不需要 unique_ptr 的删除器对象。最多,您只需要一个参数来告诉您指针类型是什么,默认为T*

所以这是一个很好的理由不这样做。

【讨论】:

  • 关于你答案的最后一点,假装专门default_delete 来调用自定义destroy 而不是delete 是有效的,对于@987654344 使用删除器仍然是有好处的@ 当你想对同一个 T 使用不同的删除器时。这可能不是一个很好的用例(T 上的强类型可能是个好主意),但它确实存在。
  • 所以,总结一下:这三个问题都不是,但是std::default_delete 的任何有用的专业化都是无效的,所以这并不重要?
猜你喜欢
  • 2011-09-13
  • 1970-01-01
  • 2014-03-25
  • 2013-05-05
  • 1970-01-01
  • 1970-01-01
  • 2011-09-09
  • 1970-01-01
相关资源
最近更新 更多