【问题标题】:C++ shared+ptr use_count for nullptrC++ shared_ptr use_count for nullptr
【发布时间】:2018-07-30 19:33:13
【问题描述】:

我定义并分配了 2 个shared_ptrs nullptr。在案例 1 中,我使用默认构造函数,在案例 2 中,我使用带有 delete 方法的构造函数。

shared_ptr<int> sptr2(nullptr);

cout << "sptr2 use_count: " << sptr2.use_count() << endl;

shared_ptr<int> sptr6(nullptr, default_delete<int>());

cout << "sptr6 use_count: " << sptr6.use_count() << endl;

输出是:

sptr2 use_count: 0
sptr6 use_count: 1

我不明白为什么 sptr6 在没有任何有效指针的情况下使用计数为 1。

g++ (GCC) 4.8.5 20150623(红帽 4.8.5-16)

【问题讨论】:

  • GCC 4 系列中的 C++11 实现不完整。即使存在一个类或函数,它也可能没有完全实现或包含错误。我强烈建议您更新到更高版本的 GCC。
  • 顺便说一句,shared_ptr&lt;int&gt; sptr2(nullptr); 在技术上不是默认构造,那就是shared_ptr&lt;int&gt; sptr2; 结果应该是一样的,但你没有使用默认构造函数。至少根据this shared_ptr constructor reference.

标签: c++ c++11 shared-ptr smart-pointers


【解决方案1】:

根据 C++11 和 C++14 中的 [util.smartptr.shared.const](我还没有检查 C++17),如果您不传递任何参数,shared_ptr 是“空的”。否则,shared_ptr“拥有p”即使pnullptr_t

如果提供了删除器,这是有道理的(毕竟你必须将删除器存储在某个地方),但是对于单参数构造函数来说,这样做的目的是什么,我不能说。

我显然并不孤单,因为实际函数的 C++11/C++14 规范 ([util.smartptr.shared]/1) 列出了 constexpr shared_ptr(nullptr_t) : shared_ptr() { },这表明了这种构造(但不是提供删除器的构造)应该导致“空”shared_ptr!

但这与列出的语义直接矛盾(专门将use_count == 1 作为两个示例的后置条件),因此似乎是标准中的一个错误。

GCC 显然选择支持函数规范(cppreference.com 也是如此)。在这种情况下,至少您的删除器应该是无操作的。

实际上使用默认构造函数,这样写:

shared_ptr<int> sptr;

【讨论】:

  • 另一方面,C++11 规范指定了这个构造函数行:constexpr shared_ptr(nullptr_t) : shared_ptr() { }。所以传递nullptr 应该使shared_ptr 对象为“空”(§20.7.2.2.1)
  • @Someprogrammerdude 关于 §20.7.2.2.1,该引用正确吗?它似乎与 shared_ptr 没有任何关系?
  • @Someprogrammerdude:现在怎么样了?
  • @Someprogrammerdude:我已经要求std-discussion 权衡一下。他们可以在标准中修复它或让我直截了当;)
  • @ArneVogel:哦,你可能是对的 - 我错过了它的授权。我认为您或 SPD 应该写一个答案 tbh
【解决方案2】:

shared_ptr 设计导致行为不同的原因。 SharedPtr 指的是“控制对象”,控制对象指的是“用户对象”。

如果使用 nullptr (sptr2) 初始化 shared_ptr,则不会创建控制对象。构造函数什么都不做。

如果你用deleter (sptr6)初始化shared_ptr,就会创建控制对象来存储deleter。因此,如果创建了控制对象,它的引用计数必须为 1。

【讨论】:

  • PavloK 控制对象应该是一个实现细节。
  • @Oliv 但是删除器仍然需要存储,我认为这是这种行为的一个很好的理由。
  • @Someprogrammerdude:嗯,有道理。
  • @all。我不确定我是否完全理解您在我的帖子中要说的内容。无论如何......为什么你不会惊讶于控制对象仍然活着而至少有一个weak_ptr引用它。所有 shared_ptr 对象完成其生命周期,用户对象被删除,但如果存在 week_ptr,则 control_object 仍然存在。
  • @Someprogrammerdude 无论计数器存储在控制对象上。所以理论上它可以被设置为零。我相信在没有 share_ptr 到数组的情况下,在 c++14 之前实现 shared_ptr,其中基于 count==0 的假设意味着如果弱计数为空,则可以销毁控制对象。他们只是不想强迫实现者修改 shared_ptr。
猜你喜欢
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-11
  • 2022-12-12
  • 2020-10-08
相关资源
最近更新 更多