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

为何需用lock()配合std::weak_ptr安全获取std::shared_ptr及相关疑问

为何必须用lock()配合std::weak_ptr才能安全提取std::shared_ptr?

以下是从std::weak_ptr获取std::shared_ptr的两种实现方式示例:

#include <memory>
#include <iostream>

void print_shared1(std::weak_ptr <int> wp)
{
    // 始终能安全获取指针
    std::shared_ptr <int> sp(wp.lock());
    std::cout << "wp = " << (sp ? *sp : 0) << std::endl;
}

void print_shared2(std::weak_ptr <int> wp)
{
    // 若指针已释放可能崩溃
    std::shared_ptr <int> sp(wp);
    std::cout << "wp = " << (sp ? *sp : 0) << std::endl;
}

int main(int argc, char* argv[]) 
{
    std::shared_ptr <int> s = std::make_shared<int>(1);
    std::weak_ptr <int> w = s;

    print_shared1(w);
    print_shared2(w);

    s.reset();
    
    print_shared1(w);
    print_shared2(w);
}

运行程序后输出:

wp = 1
wp = 1
wp = 0
terminate called after throwing an instance of 'std::bad_weak_ptr'
  what():  bad_weak_ptr
Aborted (core dumped)

显然直接通过构造std::shared_ptr访问std::weak_ptr并非始终安全,针对两个疑问解答如下:


1. 为什么print_shared2中构造std::shared_ptr不采用lock()的语义?

这是C++标准对两种操作的设计意图差异导致的:

  • std::shared_ptr<T>(std::weak_ptr<T>)构造函数的定位是明确依赖对象存活的场景。它要求传入的weak_ptr必须指向存活对象,否则直接抛出std::bad_weak_ptr异常,属于「快速失败」设计——如果你确定对象一定存在,用这种方式能立刻暴露不符合预期的情况。
  • wp.lock()的定位是不确定对象是否存活的场景,它会尝试将weak_ptr提升为shared_ptr:对象存活则返回有效shared_ptr,对象已销毁则返回空shared_ptr,让开发者可以自行处理空指针情况,属于「容错式」设计。

二者为不同使用场景设计,不能互相替代。

2. std::bad_weak_ptr有何用途?

std::bad_weak_ptr是C++标准库提供的异常类型,专门用于:
当你尝试从已过期(指向对象被全部shared_ptr销毁)或本身无效的weak_ptr构造shared_ptr时,抛出该异常。

它的核心作用是将逻辑错误显性化:如果你写代码时假设weak_ptr指向的对象一定存在,但实际并非如此,这个异常会立刻告诉你问题所在,而非让后续代码使用空指针/野指针导致更隐蔽、更难排查的崩溃(比如内存访问错误)。开发者可以捕获该异常,针对性修正逻辑或处理对象已销毁的情况。


内容的提问来源于stack exchange,提问作者Peter Fletcher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 18:06:16