【问题标题】:How is shared_ptr reference counter laid out?shared_ptr 引用计数器是如何布局的?
【发布时间】:2013-07-11 17:27:28
【问题描述】:

我对 C++ 很陌生。我一直认为shared_ptr 将单独的指针保持到单独的引用计数器变量。但是今天突然发现其实我不知道它是怎么布局的,而且引用值在C++中不需要有分隔指针。

如果布局是由标准定义的,std::shared_ptr 的正确预期布局是什么?

【问题讨论】:

  • 标准没有为大多数类定义“布局”(例如所需的数据成员),std::shared_ptr 就是其中之一。它只需要一定的行为,包括一些成员函数和非成员函数的存在。
  • @DyP 你能把这个重写为答案吗?这样我就可以选择它了。
  • 除了公认的正确答案之外,这里还有一些显示典型 shared_ptr 布局的 ascii 艺术:stackoverflow.com/questions/8645835/…
  • @HowardHinnant 这正是我想要的。谢谢。

标签: c++11 shared-ptr memory-layout


【解决方案1】:

C++ 标准没有为任何非标准布局类定义它应该如何在内存中布局,例如[class.mem]/13

分配具有相同访问控制(第 11 条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。未指定具有不同访问控制的非静态数据成员的分配顺序(第 11 条)。实现对齐要求可能会导致两个相邻的成员不能立即分配;管理虚拟功能 (10.3) 和虚拟基类 (10.1) 的空间要求也是如此。

标准布局类型有一些例外/简化,但对于类的内存布局没有通用规范。

这也适用于标准库中的类。除此之外,标准只定义了这些类的要求,其中一些是成员函数签名意义上的“接口”。在 [objects.within.classes] 中非常明确:

1) 第 18 至 30 条和附录 D [即标准库]不指定类的表示,并有意省略类成员的规范(9.2)。实现可以根据需要定义静态或非静态类成员,或两者兼而有之,以实现第 18 条至第 30 条和附录 D 中指定的成员函数的语义。

2) 某些类的对象有时需要其类的外部规范来存储数据,显然是在成员对象中。为了说明起见,一些子条款为满足类的外部规范的类的私有成员对象提供了代表性声明和语义要求。此类成员对象的声明和相关成员类型的定义后跟仅以说明结尾的注释,如:

streambuf* sb; // exposition only

也就是说,对std::shared_ptr 所需功能的一些说明:

  • 您需要将拥有对象的引用计数存储在一个动态分配的对象中,该对象包含此所有权信息(dyn.alloc。因为不清楚哪个shared_ptr 是最后一个活着的,而最后一个必须释放它)
  • 您还需要存储此所有权信息对象的引用计数以供weak_ptr 使用,因为weak_ptr::expiredweak_ptr::lock 等可能不会失败(通过访问冲突,例如)

迂腐的旁白:标准不要求shared_ptr泄漏内存,但 PC 类型架构的典型实现可能会使用动态内存分配。

std::make_shared btw 被认为比使用 std::shared_ptr 的 ctor 更快,因为它可以在一次分配中为拥有的对象和所有权信息对象分配内存(标准说“实现应该执行不超过一个内存分配。”,虽然这只是一个备注)。

【讨论】:

    猜你喜欢
    • 2016-01-02
    • 1970-01-01
    • 1970-01-01
    • 2015-06-24
    • 2012-10-31
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多