You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何空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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:50:23