shared_ptr循环引用导致析构停滞而非死锁,因引用计数无法归零;应以weak_ptr打破循环,由生命周期依赖方向决定使用位置;shared_from_this()要求对象已被shared_ptr管理;多线程下控制块线程安全但对象本身不安全。

为什么 shared_ptr 在循环引用时会导致析构死锁
shared_ptr 的引用计数机制本身不会直接引发死锁,但当两个对象互相持有对方的 shared_ptr 时,各自的引用计数永远无法归零,析构函数根本不会被调用——这看起来像“死锁”,实则是资源泄漏加析构停滞。典型场景是 A 类里存着 shared_ptr<b></b>,B 类里又存着 shared_ptr<a></a>,销毁任意一方都无法触发对方析构。
用 weak_ptr 打破循环引用的具体写法
weak_ptr 不增加引用计数,只在需要时通过 lock() 升级为 shared_ptr。关键在于:谁该用 weak_ptr,谁该用 shared_ptr——通常由对象生命周期的依赖方向决定。
例如父子关系中,父持有子的 shared_ptr(子生命周期依附于父),子持有父的 weak_ptr(子不能延长父的生存期):
class Child {
public:
void doSomething() {
auto parent = parent_ref.lock(); // 可能返回空
if (parent) {
parent->notify();
}
}
private:
std::weak_ptr<parent> parent_ref;
};
class Parent {
public:
Parent() { child = std::make_shared<child>(); child->parent_ref = shared_from_this(); }
private:
std::shared_ptr<child> child;
};
</child></child></parent>
-
shared_from_this()只能在已由shared_ptr管理的对象中调用,否则抛出std::bad_weak_ptr - 必须确保
Parent实例本身是由shared_ptr创建的(如std::make_shared<parent>()</parent>),否则shared_from_this()失效 -
weak_ptr::lock()返回shared_ptr,非空检查必不可少;直接解引用weak_ptr会崩溃
多线程环境下 shared_ptr 的线程安全边界
shared_ptr 的控制块是线程安全的(引用计数增减原子),但其所指向的对象不是。如果多个线程同时调用对象的成员函数并修改内部状态,仍需额外同步(如 mutex)。析构本身不会并发发生——因为引用计数归零是原子操作,且只会有一个线程真正执行析构。
- 不同线程对同一
shared_ptr实例的拷贝/赋值/重置是安全的 - 不同线程对不同
shared_ptr实例(指向同一对象)的操作也是安全的 - 但若一个线程正在析构对象,另一线程仍持有该对象的裸指针或引用并访问,属于未定义行为
- 避免在析构函数里再调用可能引发新 shared_ptr 构造的逻辑(比如回调注册表里触发清理),容易形成间接循环或竞态
替代方案:明确所有权 + 原始指针 + RAII 封装
并非所有场景都适合智能指针。当对象生命周期完全由外部明确管理(如栈对象、单例、容器唯一拥有者),用原始指针 + RAII 封装反而更清晰、无开销、无循环风险。
例如:
class Owner {
std::vector<:unique_ptr>> widgets;
public:
void addWidget() { widgets.push_back(std::make_unique<widget>(*this)); }
};
class Widget {
Owner& owner; // 非拥有式引用,不参与生命周期管理
public:
Widget(Owner& o) : owner(o) {}
void notify() { owner.onWidgetEvent(*this); }
};
</widget></:unique_ptr>
-
Owner用unique_ptr明确独占所有权,Widget用引用或原始指针表达非拥有关系 - 避免在
Widget中存储shared_ptr<owner></owner>或weak_ptr<owner></owner>,除非它真需要异步延迟访问 - 这种设计下,析构顺序由作用域或容器控制,不存在引用计数僵局
循环引用问题本质是建模偏差:把“观察”“回调”“上下文引用”误当成“共享所有权”。拆清谁真正负责销毁,比强行套用智能指针更治本。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











