2011-11-23 62 views
1

一般問題
現在我已經閱讀了很多關於智能指針的知識,並且在很多情況下共享指針看起來都是「完美的」。不過,我也讀過關於循環引用或類似的東西? shared_ptr哪裏不能用?我有一個難以置信的時間,有人能給出一個微不足道的例子來證明這一點嗎?智能指針 - 爲什麼使用它們,以及使用哪一個?

另外我真的想知道,weak_ptr提供的常規指針不能提供什麼? - 由於它們不增加引用計數,它們不能保證它們指向的內存仍然有效嗎?

我的個人項目:
在我2「全球性」的容器(包括容器是很快的一類裏面移動),兩者都充滿了「對象」的項目。然而,兩者都應該「指向」同一個對象。一個對象不能存在於這些容器之外,並且一個容器不應該包含它,而另一個容器不應該包含它。

目前我只是使用普通的指針爲此,並有一個createObject & destroyObject方法來管理內存。

這是不錯的設計?我應該使用智能指針嗎?

+1

看看這個線程的開始:[智能指針(增強)解釋](http://stackoverflow.com/questions/569775/smart-pointers-boost-explained) – Bart

+0

看到這裏:http:// stackoverflow.com/questions/6675651/when-should-i-use-c-pointers-over-smart-pointers – Azodious

+0

'weak_ptr'保證它將指向一個有效的對象或將是'null'。與原始指針對比的是,無法判斷指向的對象是否已被銷燬。 –

回答

2

爲了回答您的各種問題:

循環引用是當每2個不同的對象有一個shared_ptr其他對象。

例如:

struct Foo { 
    shared_ptr<Bar> m_bar; 
}; 

struct Bar { 
    shared_ptr<Foo> m_foo; 
}; 


void createObject() 
{ 
    shared_ptr<Foo> foo(new Foo); 
    shared_ptr<Bar> bar(new Bar); 
    foo->m_bar = bar; 
    bar->m_foo = foo; 
    //Neither of these objects will be released here 
} 

這可能會導致無論是對象被free'd,爲Foo將始終保持引用計數欄上方1,和Foo不會free'd因爲bar將始終保持其參考計數高於1.

這是weak_ptr可以克服的情況,因爲它們不增加引用計數。正如你所指出的那樣,這不會阻止ptr被釋放,但它確實允許你在使用它之前檢查該對象是否存在,這是你不能用標準指針做的。

至於你提供的例子,你應該幾乎總是使用智能指針而不是原始指針,因爲它們允許對象在超出範圍時自動釋放,而不必確保它自己完成,這可能容易出錯。在有例外的情況下尤其如此,它可以輕鬆地跳過您編寫的任何發佈代碼。

例如,下面的代碼可能會導致問題:

Foo* foo = createObject(); 
foo.doSomething(); 
deleteObject(foo); 

如果foo.doSomething是除外,然後DeleteObject的永遠不會調用和Foo不會free'd。

然而,這將是安全的:

shared_ptr<Foo> foo = createObject(); 
foo.doSomething(); 

shared_ptr的會自動在代碼塊結束時發佈的,無論是否發生異常。

有指針和智能指針在這裏的一個相當不錯的討論:Pointers, smart pointers or shared pointers?

+0

您的示例中沒有任何內容(包含語法錯誤)必然會構造一個循環。這可能是一個非常有效的鏈表,其中奇數和偶數元素是不同類型的。 –

+0

確實,這是一個不好的例子。我會編輯 – obmarg

0

如果使用shared_ptr,則最終可能會出現一圈指針(例如, p1 - > p2 - > p3 - > p1,然後他們永遠不會被釋放。要打破圓圈,可以使用weak_ptr,例如 p1 sp-> p2 sp-> p3 wp-> p1,然後共享指針可以自動釋放。

需要記住的一點是,即使智能指針可以讓您避免明確地刪除資源,但它們不是銀色的子彈,而且仍然可能會導致內存「泄漏」,例如,當您有一圈指針時,而在一個複雜的系統中,他們可能很難找到。

+0

「_打破你可以使用weak_ptr_的圈子'''weak_ptr'沒有參考語義,但參考語義較弱。 IOW,**'weak_ptr'具有完全不同的語義,並且不是'shared_ptr'的替代品。** – curiousguy

1

這裏的循環引用的一個簡單的例子:

struct Node { 
    shared_ptr<Node> next; 
}; 

int main() 
{ 
    shared_ptr<Node> n1(new Node), n2(new Node); 
    n1->next = n2; 
    n2->next = n1; 
} 

n1n2指向對方,讓他們形成一個循環。香草shared_ptr只能與directed acyclic graphs(DAG)一起使用。對於循環指令,有weak_ptr,它不會在循環中搞亂參考計數,但應小心使用。 DAG或樹結構中的後向指針是weak_ptr的有效用例,允許您在結構中備份。

關於你目前的項目:是的,嘗試shared_ptr,它可能會讓你的生活更輕鬆。您可以使用use_count() >= 2檢查兩個容器中是否存在對象;請注意0​​,因爲您可能會將指向包含對象的指針交給客戶端代碼,這會增加引用計數。

+0

實際上,客戶端代碼將被賦予對OBJECTS的引用,以試圖隱藏底層內存模型。 – paul23

+0

「_DAG或樹形結構中的後綴指針是weak_ptr的有效用例,允許您在結構中進行備份。」僅當您可以隨時接受這些指針時纔會變爲null。 IOW,**只有當你不需要反向指針**時,如果提供了它,可以使用它。 – curiousguy

0

爲了協調兩個不同的容器中的具體問題,一種方法是一類將保持不變這一捆綁範圍內的兩個集裝箱。

另一種是使用Boost.MultiIndex已經提供這種保證。採取一些練習,我仍然建議使用相關方法來包裝訪問,以便爲用戶提供以業務爲中心的界面。

相關問題