C++ 析構函數問題?
(析構函數釋放對象使用的資源,並銷毀對象的非static數據成員) 這句話是c++ primer 5th上說的。 我的問題是:銷毀對象的成員,這個銷毀是什麼意思? 我試了一下,定義了一個類之後顯示調用析構函數,發現非static對象只是執行了自己的析構函數,內置類型完全沒變化,而已還可以列印出這些數據成員的值。銷毀這個詞的意思我理解為這個對象生命期到了,內存被回收了。但析構函數為啥會銷毀數據成員呢? 求大神講講!
-----------------------------------------------------------------------------------------------------------
#include &
#include &
using namespace std;class B
{
public:
~B()
{
cout &<&< "______________________________________________________" &<&< endl; } int a = 1; int b = 2; string s{ "ssssssss" }; }; class D { public: ~D() = default; B m; }; int main() { D demo; demo.~D(); cout &<&< demo.m.a &<&< endl &<&< demo.m.b &<&< endl &<&< demo.m.s &<&< endl; system("pause"); return 0; }運行結果:
D裡面有一個B成員, 顯示調用了D的析構函數後, 發現B的析構函數也被調用了. 析構函數那個隱式的析構部分是銷毀數據成員, 也就是調用數據成員的析構函數對嗎? 所以一個對象執行了析構函數後就可以說這個對象被銷毀了吧? 只不過內存不一定被回收掉, 我的理解對了嗎?
所謂"銷毀"其實是個抽象的說法。事實上,你不把析構函數用來「銷毀」什麼東西也無所謂。對析構函數你可以先這麼理解:「對象生命周期結束時自動調用的函數」。如果你理不清抽象層級,考慮什麼銷毀不銷毀的只能徒增困惑。
- 銷毀 = destroy
- 析構 = destruction
destruction 是 destroy 的名詞形式……
---析構函數不會釋放資源,只是用來銷毀類里的對象的。題主說想知道除了函數體外還隱式幹了什麼,最好的辦法是查資料。比如 C++11 §12.4/8:After executing the body of the destructor and destroying any automatic objects allocated within the body, a destructor for class X calls the destructors for X』s direct non-variant non-static data members, the destructors
for X』s direct base classes and, if X is the type of the most derived class, its destructor calls the
destructors for X』s virtual base classes.
大意是,執行完析構函數函數體、銷毀函數體內分配的所有自動對象後:
- X 的析構函數調用 X 里所有直接的非 static 成員的析構函數
- 然後 X 的析構函數會去調用 X 的所有直接父類的析構函數
- 如果 X 是該對象本身的類型(most derived class),還會再去調用 X 的所有虛基類的析構函數
然後就沒有了,就這些。
---順帶一提,題目裏手動調用 demo 析構函數以後再去訪問其成員,是未定義行為。析構函數不是用來銷毀數據的,而是通知他對象數據要銷毀了。他沒法銷毀自己,但是在這個對象動態分配的其他對象,應該銷毀。就像要銷毀一棟房子,某部門通知你房子要銷毀,那麼你要把請到家裡的客人趕走,把家裡的財物收拾收拾,然後,然後就沒你事情了。某部門可能馬上來拆,也有可能放那裡先不拆。當然你也可以再進去看看,但是要冒風險,房子隨時被拆。
銷毀只是一個概念,它表示在這之後這部分內存可以用來干別的事,就這麼個意思
一個C++類對象的生命周期結束時,會發生這樣的事:
- 調用類對象的析構函數。
- 調用成員變數的析構函數(如果他們是類對象)。順序與你定義的順序相反。
- 如果有基類,調用基類的析構函數。
- 回收類對象本體所佔有的內存。
這裡有幾個要點你需要注意:
- 你高興時隨時可以顯式調用析構函數,這是合法的。
- 即使你顯式調用過析構函數,這個類對象生命周期結束時仍然會再調用一次,你無法禁止。
- 執行析構函數時,順帶就會執行2和3,你無法禁止。
- 除了上面一條,析構函數的行為完全由你自己定義。你不寫,析構函數就不會做任何其他事情。
現在回到你的問題上,你只是顯式執行析構函數,這時,對象仍然在內存中存在。由於a和b不是類,而是整數,析構函數也沒有專門調整他們的值,因此它們並不受析構函數影響。但是s因為是一個類(C++標準庫里的string是類),析構時在步驟2中隨著被一起析構了。析構後的字元串為空,也就列印不出來東西了。
析構函數經常是比表面看上去的要複雜。希望題主多多了解。
=================我是忘記的分隔線=====================
突然發現還沒解釋「銷毀」這個詞語的問題。答案很簡單和無聊:「銷毀」只是一個意義並不精確的抽象概念,並不是C++的標準術語。它可以指上述1、2、3三條,也可以指全部的4條。「銷毀」這種說法,只應該作邏輯層面上的理解,在語法層面上它沒有精確含義。stackoverflow上邊有過這樣的一個討論,你暫時不要想太多,析構函數就是在類的對象銷毀前提供給用戶進行最後操作的函數,怎麼操作在於你。
我的理解是相關內存不再屬於這個程序
但是只要那個內存區塊沒被修改,裡面的數據沒變化就能用原來的方式獲取「正確的」數據,但實際上訪問了一個不應該訪問的內存來自一隻大二的cs,說的不恰當的望指正喲西,剛剛好學到這裡,銷毀是比喻啦,不是真的把成員炸了。析構函數主要用來釋放new出來的內存,如果你不定義析構函數的話就會delete,但是如果你定義了析構函數要幹嘛,他就會程序結束的時候幹嘛
這個源文件真的能編譯成功嗎,B類里的a,b,s不能直接初始化吧
/////////////////////////
還真可以成員函數說白了可以看成局部變數,對象析構時直接銷毀,但是指針類的需要用代碼銷毀。銷毀之後並不會把數據銷毀,而是這塊數據已經不安全了。就像一塊地,你不種了,肯定不會把你之前種的莊稼砍掉把地翻新,但是不別人種不種你管不了。你種得玉米,等釋放了,拿出來的可能是豆子
析構函數只是說這個對象生命周期結束時會被調用的函數。銷毀 只是析構函數一般情況下應該做的事情,至於你是否這麼做是你的事情。一般它會指把這個對象new出來的東西delete掉吧
析構函數類似於OnDeletedelete則是另一個函數別想太多
推薦閱讀:
※只是為了建立一點編程的思想思維,學哪個語言最好?
※學習編程語言最好的方法是什麼?
※關於函數式語言的編譯優化,有沒有好的學習資料?
※怎麼樣可以很好地理解編程中的遞歸呢?
※能否通過語義直接生成解釋器?