[英]shared_ptr and weak_ptr differences
我正在閱讀Scott Meyers的“有效C ++”書。 有人提到過, tr1::shared_ptr
和tr1::weak_ptr
行為就像內置指針一樣,但是它們跟蹤多少tr1::shared_ptrs
指向一個對象。
這稱為參考計數。 這可以很好地防止非循環數據結構中的資源泄漏,但是,如果兩個或多個對象包含tr1::shared_ptrs
從而形成一個循環,則即使該循環的所有外部指針都具有零,該循環也可以將彼此的引用計數保持在零以上。被摧毀了。
那就是tr1::weak_ptrs
進入的地方。
我的問題是循環數據結構如何使引用計數大於零。 我請一個示例C ++程序。 weak_ptrs
如何解決問題? (再次,請舉個例子)。
讓我重復您的問題:“我的問題是,循環數據結構如何使引用計數大於零,請請求在C ++程序中以示例顯示。請通過示例再次用weak_ptrs
解決問題。”
這樣的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
?
答案是:如果對象之間的所有權不清楚,那么weak_ptr
就無濟於事。 如果有一個循環,程序員必須找到它並打破它。 一種替代方法是使用具有完整垃圾收集的編程語言(例如:Java,C#,Go,Haskell),或使用與C / C ++一起使用的保守的(=不完美)垃圾收集器(例如:Boehm GC) 。
shared_ptr
將引用計數機制包裝在原始指針周圍。 因此,對於shared_ptr
的每個實例,引用計數都增加一。 如果兩個share_ptr
對象share_ptr
引用,它們將永遠不會被刪除,因為它們永遠不會以零的引用計數結束。
weak_ptr
指向shared_ptr
,但並不增加其引用count.This意味着,即使存在的underying對象仍然可以被刪除weak_ptr
引用。
這種工作方式是,只要有人想使用基礎對象,就可以使用weak_ptr
創建一個shared_ptr
。 但是,如果對象已被刪除,則將返回shared_ptr
的空實例。 由於底層對象的引用計數不會因使用weak_ptr
引用而增加,因此循環引用不會導致底層對象未被刪除。
對於未來的讀者。
只想指出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;
弱指針只是“觀察”被管理對象。 他們不會“保持生命”或影響生命周期。 與shared_ptr
不同,當最后一個weak_ptr
超出范圍或消失時,指向對象仍然可以存在,因為weak_ptr
不會影響對象的生存期-它沒有所有權。 weak_ptr
可用於確定對象是否存在,並提供可用於引用該對象的shared_ptr
。
設計weak_ptr
的定義是為了使其相對簡單,因此,幾乎沒有什么可以直接使用weak_ptr
。 例如,您不能取消引用它; 沒有為weak_ptr
定義operator*
和operator->
。 您無法使用它訪問指向對象的指針-沒有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
在使用前沒有過期。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.