为什么make_shared的大小是两个指针? [英] Why is the size of make_shared two pointers?

查看:182
本文介绍了为什么make_shared的大小是两个指针?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如代码此处所示,从make_shared返回的对象的大小是两个指针。



但是,为什么 make_shared 工作方式如下所示(假设T是我们要创建的共享指针的类型):


make_shared 的结果是一个大小指针指向大小为 sizeof(int)+ sizeof(T)的分配的内存,其中int是引用计数,并且在构建/销毁指针。


unique_ptr 不知道为什么共享指针需要两个。根据我可以告诉,它需要一个引用计数,它与 make_shared ,可以放置对象本身。



另外,有没有任何实现,以我建议的方式实现(不必为特定对象 cc.c> intrusive_ptr )?

解决方案

在所有实现中,我注意到, code> shared_ptr 将拥有的指针和引用计数存储在同一个内存块中。这与其他答案所说的相反。另外,指针的副本将存储在 shared_ptr 对象中。 N1431 介绍了典型的内存布局。 / p>

这是真的,可以建立一个引用计数指针与sizeof只有一个指针。但 std :: shared_ptr 包含绝对需要sizeof两个指针的功能。其中一个特征是这个构造函数:

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

效果:构造一个存储p
并与r共享所有权的shared_ptr实例。

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

将指向 r 拥有的控制块。这个控制块将包含拥有的指针,它不必是 p ,通常不是 p 。在 shared_ptr 中, get()返回的另一个指针将是

//www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2351.htm#aliasing\"> N2351 。您可能会注意到,在引入此功能之前, shared_ptr 的大小为两个指针。在引入这个特性之前,可能已经实现了 shared_ptr 与一个指针size,但没有人,因为它是不切实际的。 N2351 后,它变得不可能。



N2351 是因为支持:

  shared_ptr< B& p(new A); 

这里, p.get() a B * ,并且通常已经忘记了关于 A 的所有类型。唯一的要求是 A * 可以转换为 B * B 可以从使用多重继承的 A 派生。这意味着当从 A 转换到 B 时,指针本身的值可能会改变,反之亦然。在此示例中, shared_ptr< B> 需要记住两件事:


  1. 在调用 get()时返回 B *

  2. 在需要时删除 A *

一个很好的实现方法是存储 B * shared_ptr 对象中的,以及具有引用计数的控制块中的 A * 。 $ b

As illustrated in the code here, the size of the object returned from make_shared is two pointers.

However, why doesn't make_shared work like the following (assume T is the type we're making a shared pointer to):

The result of make_shared is one pointer in size, which points to of allocated memory of size sizeof(int) + sizeof(T), where the int is a reference count, and this gets incremented and decremented on construction/destruction of the pointers.

unique_ptrs are only the size of one pointer, so I'm not sure why shared pointer needs two. As far as I can tell, all it needs a reference count, which with make_shared, can be placed with the object itself.

Also, is there any implementation that is implemented the way I suggest (without having to muck around with intrusive_ptrs for particular objects)? If not, what is the reason why the implementation I suggest is avoided?

解决方案

In all implementations I'm aware of, shared_ptr stores the owned pointer and the reference count in the same memory block. This is contrary to what other answers are saying. Additionally a copy of the pointer will be stored in the shared_ptr object. N1431 describes the typical memory layout.

It is true that one can build a reference counted pointer with sizeof only one pointer. But std::shared_ptr contains features that absolutely demand a sizeof two pointers. One of those features is this constructor:

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()

One pointer in the shared_ptr is going to point to the control block owned by r. This control block is going to contain the owned pointer, which does not have to be p, and typically isn't p. The other pointer in the shared_ptr, the one returned by get(), is going to be p.

This is referred to as aliasing support and was introduced in N2351. You may note that shared_ptr had a sizeof two pointers prior to the introduction of this feature. Prior to the introduction of this feature, one could possibly have implemented shared_ptr with a sizeof one pointer, but no one did because it was impractical. After N2351, it became impossible.

One of the reasons it was impractical prior to N2351 was because of support for:

shared_ptr<B> p(new A);

Here, p.get() returns a B*, and has generally forgotten all about the type A. The only requirement is that A* be convertible to B*. B may derive from A using multiple inheritance. And this implies that the value of the pointer itself may change when converting from A to B and vice-versa. In this example, shared_ptr<B> needs to remember two things:

  1. How to return a B* when get() is called.
  2. How to delete a A* when it is time to do so.

A very nice implementation technique to accomplish this is to store the B* in the shared_ptr object, and the A* within the control block with the reference count.

这篇关于为什么make_shared的大小是两个指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆