为何空weak_ptr必须存空指针,空shared_ptr却可存非空指针?
我认为对于任意合法的original参数,以下断言(1)都应成立:
#include <memory> #include <cassert> void foo(std::shared_ptr<int> original) { std::weak_ptr<int> weak{original}; std::shared_ptr<int> restored{weak.lock()}; // 显式调用lock()避免异常 assert( restored == original ); // (1) }
换句话说,我原本以为weak_ptr应当能以非所有权方式存储shared_ptr的值,并在后续锁定时恢复原始值(当然假设指向的对象仍存活)。
显然我错了,如下测试会触发断言失败:
void test() { int x = 42; std::shared_ptr<int> empty_but_nonnull{std::shared_ptr<char>{}, &x}; foo(empty_but_nonnull); }
shared_ptr可拥有一个对象,但存储指向另一个对象的指针。
若shared_ptr不拥有任何对象,则称为空;
若shared_ptr不指向任何对象,则称为空指针。
shared_ptr可以是空但非空指针的状态,这种行为被C++标准明确提及并允许:
[util.smartptr.shared.const]:
17. [注2:该构造函数允许创建存储非空指针的空shared_ptr实例。——结束注]
空但非空指针的shared_ptr可被解引用,在条件表达式中会隐式转换为true等,标准未提及这种情况属于程序格式错误,因此它是完全合法且可用的,仅表示“我指向一个无需生命周期管理的对象,比如静态存储期的全局对象”。
然而,空weak_ptr不能是非空指针的状态,C++标准明确要求它必须是空指针(重点标记):
[util.smartptr.weak.const]:
4.template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;
效果:若r为空,则构造一个存储空指针值的空weak_ptr对象
这意味着从空shared_ptr构造weak_ptr时,会丢失原始shared_ptr中存储的指针,强制所有空weak_ptr均为空指针,后续尝试重建原始shared_ptr显然会失败。
上述weak_ptr条款中重点标记部分的设计依据是什么?为何weak_ptr不应存储与原始shared_ptr相同的指针?
我最初的设想似乎并非完全不合逻辑……
编辑:已修改示例以消除所有可能的异常与未定义行为。
内容的提问来源于Stack Exchange,提问作者Igor G

