为什么make_shared的大小有两个指针?

Cli*_*ton 26 c++ shared-ptr c++11

如该代码所示这里,从make_shared返回的对象的大小是两个指针.

但是,为什么不能make_shared像下面这样工作(假设T是我们正在制作共享指针的类型):

结果make_shared一个指针大小,它指向已分配的大小内存sizeof(int) + sizeof(T),其中int是引用计数,并且这在指针的构造/销毁时递增和递减.

unique_ptrs只是一个指针的大小,所以我不确定为什么共享指针需要两个.据我所知,它需要一个引用计数,它make_shared可以与对象本身一起放置.

此外,是否有任何实现以我建议的方式实现(不必intrusive_ptr为特定对象使用s)?如果没有,我建议实施的原因是什么原因可以避免?

How*_*ant 38

在我所知的所有实现中,shared_ptr将拥有的指针和引用计数存储在同一个内存块中.这与其他答案所说的相反.另外,指针的副本将存储在shared_ptr对象中. N1431描述了典型的存储器布局.

确实可以构建一个只有一个指针大小的引用计数指针.但是std::shared_ptr包含绝对需要两个指针大小的功能.其中一个功能是这个构造函数:

template<class Y> shared_ptr(const shared_ptr<Y>& r, T *p) noexcept;

    Effects: Constructs a shared_ptr instance that stores p
             and shares ownership with r.

    Postconditions: get() == p && use_count() == r.use_count()
Run Code Online (Sandbox Code Playgroud)

它中的一个指针shared_ptr将指向由其拥有的控制块r.该控制块将包含所拥有的指针,该指针不必是p,通常不是p.其他指针的shared_ptr,返回的一个get(),将是p.

这被称为混叠支持,并在N2351中引入.您可能会注意到shared_ptr在引入此功能之前有两个指针的大小.在引入此功能之前,可能已经实现shared_ptr了一个指针的大小,但没有人这样做,因为它是不切实际的.在N2351之后,它变得不可能.

N2351之前不切实际的原因之一是因为支持:

shared_ptr<B> p(new A);
Run Code Online (Sandbox Code Playgroud)

在这里,p.get()返回一个B*,并且一般都忘记了所有类型A.唯一的要求是A*可转换为B*. B可能源于A使用多重继承.这意味着,从转换时指针本身的值可以改变A,以B和反之亦然.在这个例子中,shared_ptr<B>需要记住两件事:

  1. 如何返回B*何时get()被调用.
  2. 如何删除A*时间.

实现此目的的一个非常好的实现技术是将其存储B*shared_ptr对象中,并A*在控制块中存储引用计数.

  • 非常好.谢谢! (4认同)
  • 好的。这解释了为什么即使 B 的析构函数不是虚拟的,`shared_ptr` 也会正确删除对象。(这是针对 `shared_ptr&lt;B&gt; p(new A);` 和 `class A : B;` 的情况) (2认同)