为什么标准允许空但非空的shared_ptr?

Igo*_*r G 1 c++ language-design shared-ptr c++17

    \n
  1. 这个问题与 std::shared_ptr 不同,std::shared_ptr 为空但不为 null。\n该问题是关于解决特定问题,而我是在询问某个标准功能背后的基本原理和设计原因。
  2. \n
  3. 这个问题是另一个问题的前身:为什么需要空weak_ptr来存储空指针,而空shared_ptr允许存储非空指针?在某种程度上,它们具有相同的背景。然而,我相信这个问题是独立的并且本身是可以回答的。
  4. \n
\n

C++ 标准提供了一个别名构造函数shared_ptr

\n
template <typename T>\nclass shared_ptr\n{\n    template <typename U>\n    shared_ptr(const shared_ptr<U>& r, element_type* ptr);\n};\n
Run Code Online (Sandbox Code Playgroud)\n

这样的构造函数意味着一个shared_ptr对象可以以一种方式创建,它拥有一个对象,与 所拥有的相同r,同时存储指向另一个对象的指针 - ptr

\n

此外,标准明确允许使用此构造函数创建一个shared_ptr不拥有任何东西的对象(从而满足“空”的定义),但仍然指向某个对象(因此被限定为“非空”) :

\n
\n

[util.smartptr.shared.const]:
\n17。[注2:此构造函数允许使用非空存储指针创建空的shared_\xc2\xadptr 实例。\xe2\x80\x94 尾注]

\n
\n

构造一个空但非空的shared_ptr实例很容易被禁止,例如要求尝试构造shared_ptr具有非空存储指针的空实例应该抛出异常。

\n

但标准选择允许它。我想知道为什么以及为什么。

\n

空但非 null 的预期和规范使用场景是什么shared_ptr

\n

eca*_*mur 5

std::shared_ptr别名构造函数是在标准化过程中添加到N2351“Improving shared_ptr for C++0x, Revision 2”中的:

shared_ptr此功能以向后兼容的方式扩展了接口,增加了其表达能力,因此强烈建议将其添加到 C++0x 标准中。它不会引入源代码和二进制兼容性问题。

此时已经注意到:

[注意:此构造函数允许使用非 NULL 存储指针创建空实例。 ——注释结束。]shared_ptr

别名构造函数同时添加到boost::shared_ptr,充当测试台:https://github.com/boostorg/smart_ptr/commit/54e12d03fdfec63b4d8ff41991c4e64af6b1b4b4 https://github.com/boostorg/smart_ptr/commit/ce72827dc73ac652ed07002b75f32e01 71119c09

至于为什么允许这样做:有一个明确的替代方案,即用户shared_ptr从现有指针和无操作删除器构造 a :

auto sp = shared_ptr(p, [](auto){})
Run Code Online (Sandbox Code Playgroud)

然而,这比别名空状态效率低(因为必须分配单独的控制块)并且表达能力较差,因为不可能确定删除器是无操作。所以没有理由禁止前者。