weak_ptr
std::weak_ptr 是 C++11 引入的智能指针类型,用于解决 std::shared_ptr 循环引用的问题。它提供了一种非拥有的智能指针,允许访问由 shared_ptr 管理的对象,但不增加引用计数。
当最后一个 shared_ptr 释放对象时,weak_ptr 不会阻止资源的销毁。通过 lock() 方法可以尝试获取一个 shared_ptr,如果对象已经被销毁,则返回一个空的 shared_ptr。
核心特点
- 不拥有资源:
weak_ptr不参与对象所有权。 - 不增加强引用计数:不会延长对象生命周期。
- 可观察对象是否还活着:通过
expired()和lock()。 - 典型用途:打破
shared_ptr循环引用。
常用接口
std::weak_ptr<T> wp; // 默认构造,空 weak_ptr
std::weak_ptr<T> wp(sp); // 由 shared_ptr 构造
bool dead = wp.expired(); // 对象是否已销毁
auto sp2 = wp.lock(); // 尝试提升为 shared_ptr
long n = wp.use_count(); // 当前强引用(shared_ptr)个数
wp.reset(); // 置空
说明:
expired()只表示此刻对象是否已销毁。- 推荐优先使用
lock(),并判断返回的shared_ptr是否为空。
为什么要用 weak_ptr
两个对象互相持有 shared_ptr 时,会形成环,导致引用计数无法归零,资源泄漏。
错误示例:循环引用
#include <iostream>
#include <memory>
struct B;
struct A {
std::shared_ptr<B> b;
~A() { std::cout << "~A\n"; }
};
struct B {
std::shared_ptr<A> a; // 这里也是 shared_ptr,会形成环
~B() { std::cout << "~B\n"; }
};
int main() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b = b;
b->a = a;
}
上面程序结束时,~A 和 ~B 可能都不会被调用。
正确示例:一侧改为 weak_ptr
#include <iostream>
#include <memory>
struct B;
struct A {
std::shared_ptr<B> b;
~A() { std::cout << "~A\n"; }
};
struct B {
std::weak_ptr<A> a; // 非拥有引用,打破循环
~B() { std::cout << "~B\n"; }
void printAAlive() {
if (auto p = a.lock()) {
std::cout << "A still alive\n";
} else {
std::cout << "A already destroyed\n";
}
}
};
int main() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b = b;
b->a = a;
b->printAAlive();
}
使用建议
- 观察者关系用
weak_ptr,拥有关系用shared_ptr。 - 访问对象前总是先
lock(),不要直接假设对象存在。 - 多线程环境下,
expired()与后续访问之间可能发生状态变化,实践中应以lock()结果为准。 use_count()常用于调试,不建议依赖它做业务逻辑判断。
小结
weak_ptr 的本质是“可失效的观察句柄”。
- 它不拥有对象。
- 它能安全感知对象生命周期。
- 它是处理
shared_ptr循环引用的关键工具。