C++ 为什么make_的大小共享两个指针?

C++ 为什么make_的大小共享两个指针?,c++,c++11,shared-ptr,C++,C++11,Shared Ptr,如代码所示,make_shared返回的对象的大小是两个指针 但是,为什么不让_共享像下面这样工作(假设t是我们创建共享指针的类型): make_shared的结果是one大小的指针,它指向大小为sizeof(int)+sizeof(T)的已分配内存的大小,其中int是一个引用计数,在指针的构造/销毁时会递增或递减 unique_ptrs只是一个指针的大小,所以我不确定为什么共享指针需要两个。据我所知,它所需要的只是一个引用计数,通过make_shared,它可以与对象本身放在一起 此外,是否有

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

但是,
为什么不让_共享
像下面这样工作(假设t是我们创建共享指针的类型):

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

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


此外,是否有任何实现是按照我建议的方式实现的(而不必为特定对象使用
侵入式ptr
s)?如果没有,我建议的实现被避免的原因是什么?

引用计数不能存储在
共享\u ptr
shared_ptr
s必须在各个实例之间共享引用计数,因此
shared_ptr
必须具有指向引用计数的指针。另外,
shared_ptr
(make_shared的结果)不必将引用计数存储在分配对象的同一分配中

make_shared
的要点是防止为
shared_ptr
s分配两块内存。通常,如果只执行
shared_ptr(new T())
,则除了分配的
T
之外,还必须为引用计数分配内存
make_shared
使用placement new和delete创建
T
,将这一切放在一个分配块中。因此,您只得到一次内存分配和一次删除

但是
shared_ptr
必须仍然可以将参考计数存储在不同的内存块中,因为不需要使用
make_shared
。因此,它需要两个指针

真的,这不应该打扰你。即使在64位空间中,两个指针也没有那么大的空间。您仍然可以获得
侵入式\u ptr
功能的重要部分(即不分配两次内存)


您的问题似乎是“为什么
make_shared
应该返回
shared_ptr
而不是其他类型?”原因有很多

shared_ptr
是一种默认的、全面捕获的智能指针。如果您正在做一些特殊的事情,您可以使用一个独特的\u ptr或作用域\u ptr。或者仅用于函数范围内的临时内存分配。但是
shared_ptr
是用于任何严肃的参考工作的东西

因此,
shared\u ptr
将成为接口的一部分。您将拥有采用
共享\u ptr
的函数。您将拥有返回
共享\u ptr
的函数。等等

输入
make_shared
。根据您的想法,此函数将返回某种新类型的对象,即
使共享\u ptr
或其他任何对象。它将有自己的等价物
弱ptr
,一个
使弱ptr
。但是,尽管这两组类型将共享完全相同的接口,但您不能同时使用它们

采用
共享\u ptr
的函数无法采用
共享\u ptr
。您可以将
make_-shared_-ptr
转换为
shared_-ptr
,但您不能反过来。您将无法将任何
shared\u ptr
转换为
make\u shared\u ptr
,因为
shared\u ptr
需要有两个指针。没有两个指针它就不能完成它的工作

现在有两组指针是半不兼容的。您有单向转换;如果您有一个返回
shared\u ptr
的函数,那么用户最好使用
shared\u ptr
而不是
make\u shared\u ptr

为了指针的空间而这样做根本不值得。创建这种不兼容,只为4个字节创建两组指针?这根本不值得引起这么多麻烦

现在,也许你会问,“如果你有
make_-shared_-ptr
为什么你需要
shared_-ptr
?”

因为
make\u shared\u ptr
不够<代码>使共享并不是创建
共享
的唯一方法。也许我在用一些C代码。也许我正在使用SQLite3
sqlite3\u open
返回一个
sqlite3*
,这是一个数据库连接

现在,使用右析构函数functor,我可以将
sqlite3*
存储在
shared\u ptr
中。该对象将被引用计数。我可以在必要时使用
弱ptr
。我可以玩我通常会用的规则,我从代码< > MaxySuffy或其他任何接口得到的规则C++。它将完美地工作

但是如果存在
make\u shared\u ptr
,那么这就不起作用了。因为我无法从中创建一个。
sqlite3*
已经分配;我无法通过
make_shared
对其进行ram,因为
make_shared
构造了一个对象。它不适用于已经存在的

哦,当然,我可以做一些破解,我在C++类型中捆绑了<代码> SqLeTe3*<代码>,析构函数将销毁它,然后使用<代码> MaMaJuxBuffy/Cuff>创建该类型。但是使用它变得更加复杂:你必须经历另一个间接层次。你必须经历打字的麻烦等等;上述析构函数方法至少可以使用一个简单的lambda函数

智能指针类型的激增
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()
shared_ptr<B> p(new A);