標籤:

同一個指針,作為父類類型被delete,但作為子類類型仍能訪問成員變數,為什麼?

class Father {
public:
Father(){cout &<&< "father construct" &<&< endl;} virtual ~Father(){cout &<&< "father desturct" &<&< endl;} string father_; }; class Son:public Father { public: Son(){cout &<&< "son construct" &<&< endl;} ~Son() {cout &<&< "son destruct" &<&< endl;} string son_; }; int main() { Father * father = new Son(); //father-&>father_ = "baba"; //這裡如果解開注釋,下面就會報錯
Son* son = (Son*) father;
son-&>son_ = "sunzi";
delete father;
cout &<&< son-&>son_&<&< endl; //這裡居然不報錯,而且沒有core!!!!!! return 0; }

程序輸出如圖:

問題描述:

在看一個老程序的代碼時,發現代碼中有一處寫的有問題,我簡化成了上面的代碼,主要特點是:

1. 子類對象分別有父類指針和子類指針指向

2. delete 父類指針

3. 子類仍然能夠訪問自己的成員變數

請問為什麼會這樣,(我明白這樣寫肯定不對,不過還是很好奇為什麼這樣可以工作)


訪問已經釋放的內存是不定義行為,什麼都可以發生,包括不把程序搞掛掉,或者存檔之後下次啟動讀進度的時候把程序搞掛掉。

微軟以前搞過一回讓這些釋放了內存還繼續使用指針的程序立刻崩潰,結果崩潰的程序太多,不得不改回去了(https://support.microsoft.com/en-us/help/194550/fix-freeing-memory-multiple-times-may-cause-an-application-error-in-visual-c)。


你用VC++跑debug模式就報錯了。C++標準從來沒說過訪問一個被delete的對象就一定會發生什麼,所以什麼都不發生也是沒問題的。


運氣好而已。你這是對空懸指針做解引用,按標準這是未定義行為,出什麼結果都有可能。

從大多數的實現來說,delete操作只是告訴操作系統(或者CRT的內存池)這塊內存不用了還給你。操作系統(或者CRT的內存池)收到消息後只會在內存登記表裡做一下登記,不會馬上去動這塊內存中的內容。所以你這個指針看起來還能拿到之前的數據。


內存還沒有擦除而已,這裡的delete只是告訴操作系統,這塊內存地址變成可用的了,但由於沒有分配新的東西到這塊內存地址,所以內存的內容暫時沒有變化。你可以delete之後,在訪問野指針之前,多做幾次小內存的申請釋放,應該就能出現異常。

實際上大多數刪除操作(包括刪磁碟文件)都不會去做真正意義上的擦除。


你人死了也不可能一瞬間就分解到連骨頭都不剩啊o(-`д′- ?)


父類型也可以訪問也沒什麼奇怪的


系統回收了你的就會如願出core 了


好標準的野指針。

內存被釋放了並不代表系統就一定會幫你把內存清零,所以你依然能訪問。


推薦閱讀:

這次dmlc發布的深度學習框架mxnet比之caffe有什麼優缺點?
C++什麼情況下,需要重載一個成員函數的const和非const版本?
為什麼 C++ 有指針了還要引用?
C語言如何執行buf中的代碼?

TAG:程序 | C |