为何需用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
相关产品推荐
相关产品推荐

