`std::shared_ptr` 不应该默认使用 `std::default_delete` 吗?

Ded*_*tor 5 c++ default shared-ptr delete-operator c++20

std::default_delete 可以专门化以允许std::unique_ptrs轻松管理必须通过调用某些自定义销毁函数而不是使用 来销毁的类型delete p;

\n\n

基本上有两种方法可以确保对象由std::shared_ptrC++ 中的 a 管理:

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

  2. \n
  3. 之后使用构造函数.reset().

  4. \n
\n\n

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

\n\n

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

\n\n

引自 n4659 (~C++17):

\n\n
\n
template<class Y> explicit shared_ptr(Y* p);\n
Run Code Online (Sandbox Code Playgroud)\n\n

4 要求:Y必须是完整的类型。表达式delete[] p,whenT是数组类型,或delete p,whenT不是数组类型,应具有良好定义的行为,并且不应引发异常。
\n 5 E\xef\xac\x80ects:当T不是 Array 类型时,构造一个shared_ptr拥有指针的对象p。否则,构造一个shared_ptr拥有p和一个调用 的 unspeci\xef\xac\x81ed 类型的删除器delete[] p。当T不是数组类型时,shared_from_this启用p. 如果抛出异常,则在不是数组类型delete p时调用,否则调用。\n 6 后置条件:. \n [\xe2\x80\xa6]Tdelete[] p
use_count() == 1 && get() == p

\n\n
template<class Y> void reset(Y* p);\n
Run Code Online (Sandbox Code Playgroud)\n\n

3 E\xef\xac\x80ects:相当于shared_ptr(p).swap(*this).

\n
\n\n

我的问题是:

\n\n
    \n
  1. 是否有一个最好的充分理由不指定使用它std::default_delete
  2. \n
  3. 该更改是否会破坏任何有效(并且可能有用?)的代码?
  4. \n
  5. 是否已经有这样做的提案?
  6. \n
\n

Nic*_*las 4

是否有一个最好的充分理由不指定使用它std::default_delete

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

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

标准库对 的行为的要求std::default_delete<T>::operator()(T* ptr)是它“调用deleteptr。所以你对它的专业化也必须这样做。

shared_ptr因此,执行delete ptr;shared_ptr调用之间应该没有区别default_delete<T>{}(ptr)

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


来自评论:

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

但这不是要求所说的。delete上面写着“召唤ptr”。它没有说一些更含糊的内容,例如“结束由”指向的对象的生命周期ptr“或”“销毁由”引用的对象ptr。它给出了必须发生的显式代码。

而且你的专业化必须坚持到底。

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

请注意,该标准要求 的 专业化 才能default_delete<T>与调用 具有相同的效果delete p;

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

所以你这个问题的前提是不成立的。


然而,让我们暂时假设你的问题是有效的,这样的专业化是可行的。无论有效与否,专门default_delete定制删除程序行为并不是这样做的预期方法。unique_ptr如果这是意图,那么您根本不需要删除器对象。最多,您只需要一个参数来告诉您指针类型是什么,默认为T*.

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