gpt4 book ai didi

c++ - cpp make_shared 用于空指针

转载 作者:塔克拉玛干 更新时间:2023-11-03 08:11:37 28 4
gpt4 key购买 nike

我想使用 std::make_shared 创建一个空指针。由于 make_shared 应该比 shared_ptr(new T) 快,并且异常保存我想知道是否有库函数以 make_shared 的方式创建 shared_ptr(new foo)。

最佳答案

您可以转换任何 shared_ptr<foo>shared_ptr<void>没有与 make_shared 相关的效率损失:

#include <memory>

struct foo {};

int main()
{
std::shared_ptr<void> p = std::make_shared<foo>();
}

转换保持 foo和同一内存分配中的引用计数,即使您现在通过 void* 引用它.

更新

这是如何工作的?

一个std::shared_ptr<foo>的一般结构是两个指针:

                          +------> foo
| ^
p1 ---------> (refcount, +) |
p2 --- foo* -----------------------+

p1指向包含引用计数(实际上是两个引用计数:一个用于强所有者,一个用于弱所有者)、删除器、分配器和指向对象“动态”类型的指针的控制 block 。 “动态”类型是 shared_ptr<T>构造函数看到,说 Y (可能与 T 相同,也可能不同)。

p2类型为 T* T在哪里是一样的Tshared_ptr<T> .将其视为存储对象的“静态”类型。当您取消引用 shared_ptr<T> 时, 它是 p2被取消引用。当你销毁一个 shared_ptr<T> ,如果引用计数变为零,则控制 block 中的指针有助于销毁 foo。 .

在上图中,控制 block 和foo是动态分配的。 p1是一个拥有指针,控制 block 中的指针是一个拥有指针。 p2是一个非拥有指针。 p2唯一 功能是取消引用(箭头运算符、get() 等)。

当您使用 make_shared<foo>() 时, 执行有机会把 foo就在控制 block 中,与引用计数和其他数据一起:

p1  ---------> (refcount, foo)
p2 --- foo* --------------^

这里的优化是现在只有一个分配:现在嵌入了 foo 的控制 block 。 .

当上述转换为 shared_ptr<void> 时,所有发生的事情是:

p1  ---------> (refcount, foo)
p2 --- void* -------------^

p2 的类型从 foo* 更改至 void* .就是这样。 (除了递增/递减引用计数以说明临时文件的复制和销毁——这可以通过从右值构造来省略)。当引用计数归零时,仍然是控制 block 破坏了foo。 , 通过 p1 找到. p2不参与销毁操作。

p1实际上指向控制 block 的通用基类。这个基类不知道类型 foo存储在导出的控制 block 中。派生控制 block 构建于shared_ptr的构造函数当时的实际对象类型 Y众所周知。但是从那以后shared_ptr只能通过 control_block_base* 与控制 block 通信.所以像破坏这样的事情是通过虚函数调用发生的。

shared_ptr<void> 的“移动构造”来自右值 shared_ptr<foo>在 C++11 中只需要复制两个内部指针,而不必操作引用计数。这是因为右值 shared_ptr<foo>无论如何都要离开了:

// shared_ptr<foo> constructed and destructed within this statement
std::shared_ptr<void> p = std::make_shared<foo>();

这在 shared_ptr 中最为明显。构造函数源代码:

template<class _Tp>
template<class _Yp>
inline _LIBCPP_INLINE_VISIBILITY
shared_ptr<_Tp>::shared_ptr(shared_ptr<_Yp>&& __r,
typename enable_if<is_convertible<_Yp*, _Tp*>::value, __nat>::type)
_NOEXCEPT
: __ptr_(__r.__ptr_),
__cntrl_(__r.__cntrl_)
{
__r.__ptr_ = 0;
__r.__cntrl_ = 0;
}

在转换构造之前,引用计数仅为 1。在转换构造之后,引用计数仍然为 1,并且在析构函数运行之前源指向空。简而言之,这就是移动语义的乐趣! :-)

关于c++ - cpp make_shared 用于空指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8645835/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com