shared_ptr和weak_ptr差异

我正在阅读Scott Meyers的“Effective C ++”一书。有人提到有
tr1::shared_ptr
tr1::weak_ptr
就像内置指针一样,但它们跟踪有多少
tr1::shared_ptrs
指向一个物体。 这称为引用计数。这在防止非循环数据结构中的资源泄漏方面效果很好,但是如果两个或多个对象包含
tr1::shared_ptrs
使得形成循环,则循环可以使彼此的引用计数保持在零以上,即使所有指向循环的外部指针都已被破坏。 这就是
tr1::weak_ptrs
进来的地方。 我的问题是循环数据结构如何使引用计数高于零。我请求一个示例C ++程序。
weak_ptrs
如何解决问题? (再次,请举例)。     
已邀请:
A
shared_ptr
围绕原始指针包装引用计数机制。因此,对于
shared_ptr
的每个实例,引用计数增加1。如果两个
share_ptr
对象相互引用它们将永远不会被删除,因为它们永远不会以引用计数为零结束。
weak_ptr
指向
shared_ptr
但不增加其引用计数。这意味着即使有一个
weak_ptr
引用,仍然可以删除下属对象。 这种方法的工作方式是,只要有人想要使用底层对象,就可以使用
weak_ptr
创建一个
shared_ptr
。但是,如果该对象已被删除,则返回一个空的
shared_ptr
实例。由于基础对象的引用计数不会随着
weak_ptr
引用而增加,因此循环引用不会导致基础对象不被删除。     
让我重复一下你的问题:“我的问题是,循环数据结构如何使引用计数高于零,请在C ++程序中请求显示示例。如何通过示例再次解决问题.5。” 像这样的C ++代码(概念上)会出现问题:
class A { shared_ptr<B> b; ... };
class B { shared_ptr<A> a; ... };
shared_ptr<A> x(new A);  // +1
x->b = new B;            // +1
x->b->a = x;             // +1
// Ref count of 'x' is 2.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, there will be a memory leak:
// 2 is decremented to 1, and so both ref counts will be 1.
// (Memory is deallocated only when ref count drops to 0)
回答你问题的第二部分:引用计数在数学上不可能处理周期。因此,
weak_ptr
(基本上只是
shared_ptr
的精简版)不能用于解决循环问题 - 程序员正在解决循环问题。 要解决这个问题,程序员需要了解对象之间的所有权关系,或者如果自然不存在这种所有权,则需要发明所有权关系。 可以更改上面的C ++代码,以便A拥有B:
class A { shared_ptr<B> b; ... };
class B { weak_ptr<A>   a; ... };
shared_ptr<A> x(new A); // +1
x->b = new B;           // +1
x->b->a = x;            // No +1 here
// Ref count of 'x' is 1.
// Ref count of 'x->b' is 1.
// When 'x' leaves the scope, its ref count will drop to 0.
// While destroying it, ref count of 'x->b' will drop to 0.
// So both A and B will be deallocated.
一个关键问题是:如果程序员无法告知所有权关系并且由于缺乏特权或缺乏信息而无法建立任何静态所有权,那么是否可以使用? 答案是:如果对象之间的所有权不明确,
weak_ptr
就无能为力。如果有一个循环,程序员必须找到并打破它。另一种补救方法是使用具有完全垃圾收集的编程语言(例如:Java,C#,Go,Haskell),或者使用与C / C ++一起使用的保守(=不完美)垃圾收集器(例如:Boehm GC) 。     
对于未来的读者。 只是想指出Atom给出的解释非常好,这里是工作代码
#include <memory> // and others
using namespace std;

    class B; // forward declaration 
    // for clarity, add explicit destructor to see that they are not called
    class A { public: shared_ptr<B> b; ~A() {cout << "~A()" << endl; } };  
    class B { public: shared_ptr<A> a; ~B() {cout << "~B()" << endl; } };     
    shared_ptr<A> x(new A);  //x->b share_ptr is default initialized
    x->b = make_shared<B>(); // you can't do "= new B" on shared_ptr                      
    x->b->a = x;
    cout << x.use_count() << endl;  
    
弱指针只是“观察”托管对象;他们不会“保持活力”或影响其生命。与ѭ6不同,当最后一个
weak_ptr
超出范围或消失时,指向的对象仍然可以存在,因为
weak_ptr
不影响对象的生命周期 - 它没有所有权。
weak_ptr
可用于确定对象是否存在,并提供可用于引用它的
shared_ptr
weak_ptr
的定义旨在使其相对万无一失,因此您几乎无法直接使用
weak_ptr
。例如,你不能取消引用它;既不定义
operator*
也不定义
operator->
为了
weak_ptr
。你不能用它访问指向对象的指针 - 没有
get()
功能。定义了一个比较函数,以便您可以将
weak_ptrs
存储在一个有序容器中,但这就是全部。     
以上所有答案都是错误的。
weak_ptr
不用于打破循环引用,它们有另一个目的。 基本上,如果所有
shared_ptr(s)
都是通过
make_shared()
allocate_shared()
来电创建的,那么如果你没有其他资源可以管理,你将永远不需要
weak_ptr
。这些函数使用对象本身创建
shared_ptr
引用计数器对象,并且将同时释放内存。
weak_ptr
shared_ptr
之间的唯一区别是
weak_ptr
允许在释放实际对象后保留引用计数器对象。因此,如果你在
std::set
中保留了大量的
shared_ptr
,如果它们足够大,实际对象将占用大量内存。这个问题可以通过使用
weak_ptr
来解决。在这种情况下,您必须确保容器中存储的
weak_ptr
在使用之前未过期。     

要回复问题请先登录注册