C++ 共享ptr的循环依赖性问题是什么?
我阅读了有关共享指针的内容,并了解如何使用。但我从未理解共享指针的循环依赖性问题,以及弱指针将如何解决这些问题。谁能把这个问题解释清楚吗?这个问题没有那么复杂。让C++ 共享ptr的循环依赖性问题是什么?,c++,shared-ptr,weak-ptr,C++,Shared Ptr,Weak Ptr,我阅读了有关共享指针的内容,并了解如何使用。但我从未理解共享指针的循环依赖性问题,以及弱指针将如何解决这些问题。谁能把这个问题解释清楚吗?这个问题没有那么复杂。让-->表示共享指针: The rest of the program --> object A --> object B ^ | \ |
-->
表示共享指针:
The rest of the program --> object A --> object B
^ |
\ |
\ v
object C
因此,我们有一个共享指针的循环依赖关系。每个对象的引用计数是多少
A: 2
B: 1
C: 1
现在假设程序的其余部分(或者至少是程序中保存指向的共享指针的部分)被销毁。然后,A的引用计数减少1,因此循环中每个对象的引用计数为1。那么什么被删除了呢?没有什么。但是我们想要删除什么呢?一切,因为程序的其余部分再也无法到达我们的任何对象
因此,本例中的修复方法是将从C到A的链接更改为弱指针。弱指针不会影响其目标的引用计数,这意味着当程序的其余部分释放A时,其引用计数将达到0。所以它被删除了,B也被删除了,C也被删除了
不过,在程序的其余部分发布A之前,C可以通过锁定弱指针随时访问A。这会将其升级为共享指针(并将a的引用计数增加到2),只要C正在积极处理a。这意味着,如果a在进行此操作时被释放,则其引用计数只会下降到1。C中使用A的代码不会崩溃,只要短期共享指针被破坏,A就会被删除。它位于锁定弱指针的代码块的末尾
一般来说,决定将弱指针放在何处可能很复杂。为了选择打破循环的位置,循环中的对象之间需要某种不对称。在这种情况下,我们知道A是程序其余部分引用的对象,因此我们知道,打破循环的地方是指向A的任何地方
shard_ptr<A> <----| shared_ptr<B> <------
^ | ^ |
| | | |
| | | |
| | | |
| | | |
class A | class B |
| | | |
| ------------ |
| |
-------------------------------------
正如我们从输出中看到的,A和B指针从未被删除,因此内存泄漏
为了避免这样的问题,只需在类A中使用弱ptr,而不是更合理的共享ptr。如果你需要谷歌银行的另一个关键字,它也被称为
retain cycle
。我现在明白了。感谢您的清晰解释。不确定这是否是解释循环依赖关系的正确示例。引用计数保存在控制块内,所有共享PTR A、B、C将指向同一控制块,计数=3。我认为这还不够解释。如果类B
的对象被破坏,会发生什么?在“为虚拟”的解释中,它破坏了自身内部的对象。因此,它调用对共享的\u ptr
对象的销毁,从而导致类A
对象的销毁。好的,A
销毁指向B的
对象的共享\u ptr
。B
的哪个状态将看到A
:已销毁/半销毁/仍然存在?然后呢?为什么跑步时会忽略这种行为?为什么它不抛出异常?
class B;
class A
{
shared_ptr<B> sP1; // use weak_ptr instead to avoid CD
public:
A() { cout << "A()" << endl; }
~A() { cout << "~A()" << endl; }
void setShared(shared_ptr<B>& p)
{
sP1 = p;
}
};
class B
{
shared_ptr<A> sP1;
public:
B() { cout << "B()" << endl; }
~B() { cout << "~B()" << endl; }
void setShared(shared_ptr<A>& p)
{
sP1 = p;
}
};
int main()
{
shared_ptr<A> aPtr(new A);
shared_ptr<B> bPtr(new B);
aPtr->setShared(bPtr);
bPtr->setShared(aPtr);
return 0;
}
A()
B()