2011-06-21 32 views
2

我有一個關於爲什麼我可以訪問某些內存塊的問題,我認爲它與我理解(或不理解)編譯器如何將內存保存在內存中的方式有​​關。這是示例代碼我的工作:C++清除的內存仍可訪問

頭文件:

#include <iostream> 
using namespace std; 

class A 
{ 
public: 
int value; 
A (int newValue = 5) 
{ 
    value = newValue; 
    cout << "A()" << endl; 
} 
~A() { cout <<"~A()" << endl; } 
void func1() {cout << "A::func1()" << endl; } 

}; 


class B : public A 
{ 
public: 
B() { A::value = 0; cout << "B()" << endl; } 
~B() { cout << "~B()" << endl; } 
virtual void func1() { cout << "B::func1()" << endl; } 

}; 

class C : public B 
{ 
public: 
C() { cout << "C()" << endl; } 
~C() { cout << "~C()" << endl; } 
virtual void func1() { cout << "C::func1()" << endl; } 
}; 

.cpp文件:

int main() 
{ 
int i; 

cout << endl; 
A* pA = new A (5); 
B* pB = new B; 
C* pC = new C; 

pA->func1(); 
pB->func1(); 
pC->func1(); 

delete pA; 
delete pB; 
delete pC; 

cout << endl; 

    //here is my first question - why don't I get a compiler error here? 
    //why does the compiler know what this is? Didn't I delete it? 
A* ppA = pC; 

    //here is my second question - why does this work? 
    //didn't I clear this memory? 
ppA->func1(); 
B bObject; 
B* ppB = &bObject; 
ppB->func1(); 


cin >> i; 

    return 0; 
} 

我的問題是正確的,在評論 - 爲什麼我沒有得到這些線路上的錯誤?

如果我更改.h文件,使func1()virtual也在A中,我確實在該行上發生訪問衝突,但仍然沒有編譯時錯誤。

感謝您的任何解釋:)

+0

我相信這可能是因爲你用delete刪除了內存,但它可能沒有寫完。因此數據可能仍然存在。但是不確定。 –

+0

僅供參考_compiler_不會將內容保存在內存中。該任務由操作系統執行。 – ALOToverflow

+0

@Francis,啊,那些善良的迂腐人物,他們只是對他們迂腐的東西有一個模糊的概念。你知道G ++在編譯一個文件的內存中「保存」了更多的東西,而不是所有的程序放在一起嗎?只是「供參考」。 – Blindy

回答

7

第一個問題的答案很簡單:指令是在編譯時寫入的。編譯器顯然不知道該值是否已被刪除,所以它只是盲目地將pC的值複製到ppA以上。

第二個問題的答案是:它可能無法正常工作。你已經進入了可怕的undefined-behavior-land。想想愛麗絲夢遊仙境,沒有貓來引導你。

基本上,當您在指針上調用operator delete時,您告訴操作系統,如果需要可以覆蓋內存。 「如果需要的話。沒有實際的內存擦除正在進行,只是承諾您不會再使用該內存塊。

因此,當您嘗試訪問虛擬表以調用func1時,數據可能仍然存在。或不。在這種情況下,你會發生崩潰(如果你幸運的話)。但是你應得的,你破壞了對操作系統的承諾,所以現在什麼都行。

編輯:注意func1從未實際使用this,所以如果它不是虛擬的,你可能會說((A*)0)->func1(),它會工作得很好。

8

編譯器不跟蹤指針是否指向一個合法的對象。這是一個複雜的分析,在大多數情況下甚至不可能。這就是爲什麼當你將一個已刪除的指針指定給另一個指針時它不會產生錯誤。

刪除對象不會自動清除對象用來佔用的內存。它將在未來的某個不確定時刻被覆蓋,所以你不應該依賴它。這被稱爲未定義的行爲,未定義行爲的特點之一就是即使它不應該也可能工作。

1

delete不會從代碼範圍中刪除名稱。這是一個將該內存標記爲不再被程序使用的命令。該內存可能會被下一次分配使用,或者在進程執行期間不再使用。

delete不會爲您清零內存。如果你需要,你可以自己做。直到它決定在那裏設置一個新分配時,那塊內存中的內容纔會被改變。使用刪除內存的指針是一個非常糟糕的想法。

0

內存釋放功能,如刪除,免費,HeapFree不會消滅內存。他們會將它們標記爲「未分配」,並且可以通過這些未分配的內存塊完成進一步的請求。同一個內存塊可以用來服務多個內存分配調用,或者只是一個調用。

這就像刪除(Shift + Deleting)文件 - 該文件實際上不會被標記爲零,它只會被標記爲「空閒空間」。與文件分配一樣,多個空閒空間可以用於一個文件(這就是爲什麼我們有「碎片整理程序」)。但是對於內存分配,服務於大內存塊分配不能由多個空閒內存塊完成。