为 `std::shared_ptr` 专门定制 `std::default_delete`

7
我有这样的想法:
namespace std {
    template<>
    class default_delete<IplImage> {
    public:
        void operator()(IplImage *ptr) const {
            cvReleaseImage(&ptr);
        }
    };
};

typedef std::shared_ptr<IplImage> IplImageObj;

我并没有找到太多关于是否支持我专门使用 default_delete, 以及 shared_ptr 是否默认也使用 default_delete 的信息。

在 Clang 5.0.0 中它可以正常工作。

那么,这是否被支持呢?

如果 STL 实现有一个不同的内部命名空间会怎样呢?那么它就找不到我的声明了吗?但是它应该会报告声明错误。


@R.MartinhoFernandes: 为什么说它是毫无意义的?这是在没有指定删除器时由 std::unique_ptr 使用的默认销毁策略。因此,这是另一种在某些由 std::unique_ptr 使用的特定类型上全局覆盖默认销毁策略的方式。我认为相同的情况也适用于 shared_ptr,并且在 Clangs STL 实现中也是如此,但根据 C++ 标准似乎并非如此。 - Albert
这是毫无意义的,因为您必须保留原始语义。这不是全局覆盖任何内容的方法,因为您不被允许创建一个不执行其他操作的专业化。 - R. Martinho Fernandes
3
在17.6.4.2.1中,还可以参考:https://dev59.com/x2oy5IYBdhLWcg3wfeIR#8513497 (“程序可以为任何标准库模板添加模板特化到命名空间std,但只有当声明依赖于用户定义的类型且特化符合原始模板的标准库要求并且没有明确禁止时方可进行。”) - R. Martinho Fernandes
1
@R.MartinhoFernandes:这只是说它必须满足与标准库相同的要求,而不是需要具有相同的语义。当然,真正的问题是std::default_delete仅适用于std::unique_ptr,而不适用于std::shared_ptr... - Chris Dodd
1
@R.MartinhoFernandes:我认为ChrisDodd的观点是,它必须以删除器的预期方式运行;保留现有语义意味着“像删除器一样运行”,而不是“执行与您尝试替换的损坏默认值相同的操作”。只要API匹配,它就会执行预期的操作(对于特定类型执行适当的清理以避免泄漏),并且只定义一个重载,那么它就是被允许的。没有要求两个不相关的程序必须就删除的含义达成一致。这仍然无法帮助std::shared_ptr,但对于std::unique_ptr很有用。 - ShadowRanger
显示剩余5条评论
1个回答

4

default_delete应该在std命名空间中定义,而且可以从std命名空间中特化实体。

namespace std {
template<class T> struct default_delete;
template<class T> struct default_delete<T[]>;

然而,你的专业化违反了一些 std::default_delete 的要求,因此是未定义行为。有关此事的引用在这里(感谢 R. Martinho Fernandes)。

然而,shared_ptr 没有指定使用 default_delete

~shared_ptr();

Effects:

  • If *this is empty or shares ownership with another shared_ptr instance (use_count() > 1), there are no side effects.

  • Otherwise, if *this owns an object p and a deleter d, d(p) is called.

  • Otherwise, *this owns a pointer p, and delete p is called.


啊,那么Clang STL实现在这方面是错误的吗?因为如果我专门化default_delete,没有自定义删除器的shared_ptr将使用我的专门化default_delete,因此不一定会调用delete p - Albert
啊,根据MartinhoFernandes在评论中的说法,我不能按照我的方式进行专门化。所以,如果shared_ptr使用它或不使用它,那么这并不重要。 - Albert
你应该添加一个链接到https://dev59.com/x2oy5IYBdhLWcg3wfeIR#8513497,以解释为什么我不能像我所做的那样专门化`default_delete`。 - Albert
1
@Albert:我没有看到任何东西禁止专门化std::default_delete<IplImage>。我认为MartinhoFernandes以一种奇怪的严格方式阅读“专业化符合原始模板的标准库要求”;标准库要求基本上只是“匹配原型(void operator()(T* ptr) const;),执行一些逻辑删除函数”,你的代码满足这些要求(只是std::shared_ptr没有声称使用它)。 - ShadowRanger

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接