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

C++中unique_ptr如何避免循环依赖问题?

问题

我们知道shared_ptr存在循环依赖问题:比如对象A有一个指向对象B的shared_ptr成员,对象B也有一个指向对象A的shared_ptr成员,那么这两个对象会一直驻留在内存直到程序结束——因为它们的引用计数永远无法降到0。

那如果把示例中的shared_ptr换成unique_ptr,为什么不会出现这种情况?此时A仍指向B,B也指向A,看起来两者都无法被销毁才对?

编辑:根据要求补充示例代码:

#include <iostream>
#include <memory>

using namespace std;

class B;

class A{
    public:
    unique_ptr<B> a_ptr;
};

class B{
    public:
    unique_ptr<A> b_ptr;
};

int main()
{
    A* a = new A();
    B* b = new B();
    a->a_ptr.reset(b);
    b->b_ptr.reset(a);

    return 0;
}
解答

首先要明确:你给出的示例代码同样会导致内存泄漏,两个对象都无法被正常销毁,只是原因和shared_ptr的循环依赖不一样。

  • shared_ptr的循环依赖是引用计数机制导致的:
    shared_ptr是共享所有权模型,每多一个指向对象的shared_ptr,引用计数就加1;当shared_ptr被销毁或重置,引用计数减1。只有当引用计数降到0时,对象才会被销毁。双向循环持有shared_ptr时,每个对象的引用计数至少为1(对方的shared_ptr还持有自己),外部引用释放后计数也无法归0,所以对象永远不会被销毁。

  • unique_ptr的情况是析构的循环死锁:
    unique_ptr是独占所有权模型,同一时刻只能有一个unique_ptr拥有对象的所有权。你的示例中,A的unique_ptr<B>持有B的所有权,B的unique_ptr<A>持有A的所有权。
    要销毁A,必须先销毁它的成员a_ptr(也就是销毁B);但销毁B时,又必须先销毁它的成员b_ptr(也就是销毁A)——这就形成了析构的死循环,两个对象的析构函数都无法被触发,最终内存泄漏。

之所以会有“unique_ptr不会出现循环依赖问题”的错觉,是因为unique_ptr的独占设计从根源上就不鼓励这种双向持有的场景:正常使用中,unique_ptr代表唯一的所有者,你不会刻意让两个对象互相成为对方的所有者,这种写法本身就违背了它的设计意图。而shared_ptr的共享模式,更容易在不经意间(比如双向链表节点)形成循环依赖。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 01:57:37