智慧型指標的死穴 迴圈引用

2022-03-14 08:23:02 字數 1385 閱讀 8507

c++最新標準c++11中已將基於引用計數的智慧型指標share_prt收入囊中,智慧型指標的使用門檻越來越低,不需要使用boost庫,我們也能輕鬆享受智慧型指標給我們帶來的方便。

智慧型指標,正如它的名字一樣,似乎是個近乎完美的聰明角色,程式設計師不用再糾結於new出來的內存在哪釋放比較合適這種問題。比如當乙個資源被多個模組共享時,程式設計師需要在所有模組的生命週期都結束時,由最後乙個不使用該指標的模組觸發指標的釋放行為,而模組的生命週期可能根本在寫**時就確定不了。

智慧型指標的出現,給不支援垃圾**機制的c++帶來了一絲曙光。下面簡單介紹一下智慧型指標的執行機制:

當我們需要從堆上申請空間時,可以將new出來的指標交由智慧型指標管理,比如:shared_ptra(new int);,這樣當a出作用域時,在a物件析構的時候,就會釋放持有的堆上指標,這是通過c++的析構函式實現的。

當乙個智慧型指標物件拷貝賦值給另外乙個智慧型指標時,比如shared_ptrb = a;a和b兩個智慧型指標指向了同一塊堆上的空間,a或b中的任意乙個物件出作用域時,都不應該釋放堆上的空間,因為還有另外乙個智慧型指標物件在引用這個堆空間,於是就引入了引用計數機制來解決這個問題。當乙個智慧型指標物件被建立時,會在堆上建立乙個用於計數的空間,當shared_ptrb = a;執行後,b物件淺拷貝a物件的計數區指標,然後將計數區的值+1。這樣就相當於拷貝賦值出的一組智慧型指標都指向同一塊堆上的資料空間,同時還共享另外一塊堆上計數區(這也是叫做shared_ptr的原因)。在智慧型指標物件析構時,不是簡單的直接釋放持有的堆資料空間,而是先將共享的引用計數-1,之後發現引用計數為0的話,才呼叫delete。

智慧型指標的實現思路也體現了c++基於物件的原則,物件應該為自己管理的資源負責,包括資源的分配與釋放,而且最好將資源的釋放與分配搞的自動化一點,典型的實現方法就是在建構函式裡分配資源,在析構函式裡釋放資源,這樣當其他程式設計師在使用這個物件時,該物件的資源問題幾乎不用額外的操心,即優雅又方便。

好啦,我是華麗的分割線。下面進入本文的重點,當迴圈引用發生時,基於計數的共享機制將會被徹底擊敗。

class b;

class a

;class b

;int main()

//b先出作用域,b的引用計數減少為1,不為0,所以堆上的b空間沒有被釋放,且b持有的a也沒有機會被析構,a的引用計數也完全沒減少

//a後出作用域,同理a的引用計數減少為1,不為0,所以堆上a的空間也沒有被釋放

}

如此一來,a和b都互相指著對方吼,「放開我的引用!「,「你先發我的我就放你的!」,於是悲劇發生了。

所以在使用基於引用計數的智慧型指標時,要特別小心迴圈引用帶來的記憶體洩漏,迴圈引用不只是兩方的情況,只要引用鏈成環都會出現問題。當然迴圈引用本身就說明設計上可能存在一些問題,如果特殊原因不得不使用迴圈引用,那可以讓引用鏈上的一方持用普通指標(或弱智能指標weak_ptr)即可。

迴圈引用 智慧型指標的死穴之一

智慧型指標的實現思路也體現了c 基於物件的原則,物件應該為自己管理的資源負責,包括資源的分配與釋放,而且最好將資源的釋放與分配搞的自動化一點,典型的實現方法就是在建構函式裡分配資源,在析構函式裡釋放資源,這樣當其他程式設計師在使用這個物件時,該物件的資源問題幾乎不用額外的操心,即優雅又方便 然後如此...

智慧型指標的迴圈引用與解決

class node node private int value int main 上面的程式不會有問題,呼叫三次建構函式,三次析構函式。下面增加乙個指向父節點的指標。class node node private int value int main 呼叫了三次建構函式,但是沒用呼叫析構函式,這...

C 程式設計智慧型指標迴圈引用解決

字型大小 小 大 2012 10 23 15 55 c 中智慧型指標的引入,使得開發人員在與記憶體的鬥爭中佔據上峰。然而凡事都不會盡善盡美,智慧型指標的迴圈引用缺陷還是會引發令人談虎色變的記憶體洩露。本文的內容就是講述,如何解決迴圈引用帶來的記憶體問題。背景 智慧型指標採用boost庫,語言c 開發...