析构的问题
關于以下代碼,哪個說法是正確的?
1
2
3
4
5
6
7
8
myClass::foo(){
delete this;
}
..
void func(){
myClass *a = new myClass();
a->foo();
}
正確答案: B 你的答案: C (錯誤)
a它會引起棧溢出
b都不正確
c它不能編譯
d它會引起段錯誤
在類的成員函數中能不能調用delete this?答案是肯定的,能調用,而且很多老一點的庫都有這種代碼。假設這個成員函數名字叫release,而delete this就在這個release方法中被調用,那么這個對象在調用release方法后,還能進行其他操作,如調用該對象的其他方法么?答案仍然是肯定 的,調用release之后還能調用其他的方法,但是有個前提:被調用的方法不涉及這個對象的數據成員和虛函數。說到這里,相信大家都能明白為什么會這樣 了。
根本原因在于delete操作符的功能和類對象的內存模型。當一個類對象聲明時,系統會為其分配內存空間。在類對象的內存空間中,只有數據成員和虛函數表指針,并不包含代碼內容,類的成員函數單獨放在代碼段中。在調用成員函數時,隱含傳遞一個this指針,讓成員函數知道當前是哪個對象在調用它。當 調用delete this時,類對象的內存空間被釋放。在delete this之后進行的其他任何函數調用,只要不涉及到this指針的內容,都能夠正常運行。一旦涉及到this指針,如操作數據成員,調用虛函數等,就會出現不可預期的問題。
為什么是不可預期的問題?delete this之后不是釋放了類對象的內存空間了么,那么這段內存應該已經還給系統,不再屬于這個進程。照這個邏輯來看,應該發生指針錯誤,無訪問權限之類的令系統崩潰的問題才對啊?這個問題牽涉到操作系統的內存管理策略。delete this釋放了類對象的內存空間,但是內存空間卻并不是馬上被回收到系統中,可能是緩沖或者其他什么原因,導致這段內存空間暫時并沒有被系統收回。此時這段內存是可以訪問的,你可以加上100,加上200,但是其中的值卻是不確定的。當你獲取數據成員,可能得到的是一串很長的未初始化的隨機數;訪問虛函數表,指針無效的可能性非常高,造成系統崩潰。
大致明白在成員函數中調用delete this會發生什么之后,再來看看另一個問題,如果在類的析構函數中調用delete this,會發生什么?實驗告訴我們,會導致堆棧溢出。原因很簡單,delete的本質是“為將被釋放的內存調用一個或多個析構函數,然后,釋放內存” (來自effective c++)。顯然,delete this會去調用本對象的析構函數,而析構函數中又調用delete this,形成無限遞歸,造成堆棧溢出,系統崩潰。
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
- 上一篇: 必须采用初始化列表一共有三种情况
- 下一篇: 或||的计算