Skip to main content
Version: 1.0

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 循环引用的关键工具。