shared_ptr如何存储deleter

How does a shared_ptr store deleter?

本文关键字:存储 deleter 何存储 ptr shared      更新时间:2023-10-16

我不明白shared_ptr如何存储我给它的deleter。

最初,使用shared_ptr<int>时,我认为它可能使用std::function<void(int*)>,但作为deleter,我可以给出任何类型的函数(或可调用对象),只要第一个参数是int*

shared_ptr如何做到这一点?

如果这是一个愚蠢的问题,我很抱歉,我是C++的新手,请原谅!

编辑:问题是:我怎么能做这样的事?我应该用什么?有什么例子吗?或者这是一个非常高级的话题?

删除程序和分配器都是类型擦除的。共享指针管理一个动态分配的、私有的、模板化的控制对象,该对象通过多态库进行访问,并存储所有类型特定的状态和功能。

std::function的实现使用了类似的思想,因为它也是一个类型擦除动态管理器类,但两者通常完全独立实现。

结果是,这两个类都相对"昂贵",只有在真正必要的时候才应该使用。否则,更便宜的、非多态的非动态解决方案通常更可取。

作为一个deleter,我可以给出任何类型的函数(或可调用对象),只要第一个参数是int*

不,不是真的。std::shared_ptr构造函数具有以下合同,见第20.8.2.2.1节([util.smartptr.shared.const]):

template<class  Y,  class  D>  shared_ptr(Y*  p,  D  d);
template<class  Y,  class  D,  class  A>  shared_ptr(Y*  p,  D  d,  A  a);
template  <class  D>  shared_ptr(nullptr_t  p,  D  d);
template  <class  D,  class  A>  shared_ptr(nullptr_t  p,  D  d,  A  a);

要求:p应可转换为T*D应为可复制结构。D的复制构造函数和析构函数不应抛出异常表达式d(p)应格式良好,应具有定义良好的行为,并且不应抛出异常。A应该是一个分配器(17.6.3.5)。A的复制构造函数和析构函数不应该抛出异常。

效果:构造一个shared_ptr对象,该对象拥有对象p和deleter d。第二个和第四个构造函数应使用a的副本来分配内存供内部使用。

后置条件:use_count() == 1 && get() == p

当无法获取内存以外的资源时,抛出:bad_alloc,或实现定义的异常。

异常安全:如果抛出异常,则调用d(p)

这个要求比deleter的第一个参数必须是正确的类型强得多。它必须是唯一的参数(没有默认参数),这样d(p)才是合法的。这比std::function<void (int*)>稍微灵活一些,因为返回类型可以是任何类型,但在异常保证方面也更受约束。

如果编译器在为deleter提供多个必需参数时没有发现问题,那么标准库实现就大错特错了。

至于如何实现它,请利用它必须是可复制可构造的这一事实。例如,以下lambda应该工作得很好,并且可以分配给std::function<void(void)>(CopyConstructable保证确保按值捕获有效):

[d, p] { d(p); }