最近面試的時候被問到一個問題是,在C++中,能否在類的成員函數中調用delete this,后來網上查了一下資料,關於這個問題說得比較好的有http://blog.sina.com.cn/s/blog_4b4cf2af0100ywgv.html
但是自己嘗試了一下,還是有點區別的。
我寫了如下代碼:
class A { public: A() { member = 1; } ~A() { member = 0; } int test() { cout << member << endl; cout << this << endl; delete this; cout << this << endl; cout << member << endl; } private: int member; }; int main(){ A a; a.test(); a.test();return 0; }
這份代碼編譯和運行都沒有問題,在test中,打印了一個1,然后打印this的地址,delete this之后,再打印this的地址,發現沒有變化,再打印member的值,發現變成了0
1. 在調用delete的時候,C++會幫我們調用這個對象的析構函數,因此member在析構函數中被置為了0
2. 調用delete只是告訴系統我們不需要這個對象的內存空間了,請求釋放它,但並不會主動幫我們把這個指針置為null,它依然指向原來的內存地址
3 有趣的是,參考的博客說,在delete this之后,會釋放掉類的對象的內存空間,因此如果不在delete this之后調用成員函數,那就沒有任何問題,如果調用了成員函數,那就會出錯,因為已經沒有這個對象的成員了。但是我發現其實還是可以的。之后我又嘗試了另外一種寫法,代碼如下:
class A { public: A() { member = 1; } ~A() { member = 0; } int test() { cout << member << endl; cout << this << endl; delete this; cout << this << endl; cout << member << endl; } private: int member; }; int main(){ A *a = new A(); a->test(); a->test(); return 0; }
這次我使用的是一個類的指針對象,然后為這個指針new一個新的對象,然后再次調用test函數,編譯過程沒有任何問題,但是在運行的時候會出現運行出錯,並且在調用delete this之后,打印出來的member都是亂值。因此在類的成員函數中調用delete this,只是當這個對象是由一個指針new出來的對象有效果,並且會出現說delete this之后對象被釋放,在delete this之后調用成員內容會出現不可知的錯誤。
那為什么會出現這兩種不一樣的結果呢?我個人猜測是因為,當我們是用A a = A()這樣產生一個局部對象的時候,由於這個對象是被壓入我們的函數棧當中,因此當你delete這個對象的指針,它也還是會存在這個函數棧當中,只有但函數棧回收的時候才會回收這個對象,而對於A *a = new A()這樣的情況,a指針對應的對象是被分配到堆當中的,當我們delete的時候,系統就可以馬上回收這個堆的內容並可能對堆的內容分布做一些優化和調整,這個時候對象對應的內容也就不存在了。
我再測試了一小段代碼:
class A { public: A() { member = 1; } ~A() { member = 0; } int test() { cout << member << endl; cout << this << endl; delete this; cout << this << endl; cout << member << endl; } private: int member; int member2; }; int main(){ A a = A(); A *ptr = &a; delete ptr; ptr->test(); return 0; }
用一個指針綁定a對象,a是一個局部的對象,然后delete這個指針的內容,然后用ptr去調用a的成員函數,這種情況也是編譯和運行完全沒有問題。