[英]Understanding delete operator in C++
考慮下面的代碼:
#include <iostream>
#include <string>
using namespace std;
class A{
public:
int x;
public:
A(){x=0;}
void fun1(){
cout << "fun1 is called \n";
cout << "Address of this is " << this <<endl;
delete this;
}
void fun2()
{
cout << "fun2 called \n";
}
~A()
{
cout << "Object Destroyed" << endl;
}
};
int main()
{
A* ptr=new A;
cout << "Address of ptr is " << ptr <<endl;
ptr->fun1();
ptr->fun2();
return(0);
}
輸出為:
$ ./TestCPP
Address of ptr is 0x20010318
fun1 is called
Address of this is 0x20010318
Object Destroyed
fun2 called
我的問題是,當我們在fun1()
調用delete
,它將破壞this
指針所指向的對象,即地址0x20010318
。 如輸出所示,它調用析構函數。 因此,在調用fun1()
之后,地址0x20010318
的對象被破壞,並且該內存被釋放。 那么為什么在輸出中可以看到fun2()
呢? 僅僅是垃圾價值嗎? 我指的是對象不存在,但在由指示位置ptr -> fun2()
的定義fun2()
仍然存在?
也有人可以解釋delete
工作原理。 例如調用new
調用operator new
和constructor
, delete
操作是否相似?
謝謝
您正在做的是技術上未定義的行為,因此,實際上,就標准而言,任何事情都可能發生。
除此之外,您所看到的實際行為可以輕松推斷。 fun2
是一個非虛擬函數。 編譯器將在編譯時解決對其的調用。 當對象被銷毀時,函數不會被銷毀。 當您調用ptr->fun2()
,編譯器將僅調用該函數。 由於該函數不依賴任何成員數據,因此輸出是完全可預測的(即使就標准而言,不是)。
這是我在null指針上調用非虛擬成員函數的演示。 顯然這是錯誤的,但是它卻完全按預期打印了語句: http : //ideone.com/pddnGt
這並不是說代碼還不錯。 您不應在代碼中具有未定義的行為。 在較低的優化級別上,出於調試目的,編譯器可能會很好地進行此類檢查,並通過錯誤消息暫停程序或引發異常。
僅僅是垃圾價值嗎? 我指的是對象不存在,但在由指示位置
ptr -> fun2()
的定義fun2()
仍然存在?
是的,這是不確定的行為,但是因為實際上沒有任何東西可以重復使用內存,所以它似乎可以“正常工作”。 雖然這實際上是一個嚴重的錯誤。 (注意: A::fun2()
的定義永遠不會到任何地方,即代碼,而不是數據,因此在程序的整個生命周期中都存在,內存位置ptr
的對象停止存在,但是其成員函數的定義不存在')
例如調用
new
調用operator new
和構造函數,delete
操作是否相似?
是的,它調用析構函數銷毀該位置處的對象,然后調用operator delete
釋放內存。
如果您的方法不是虛擬的並且不包含對成員的引用,則它可以與某些編譯器一起使用,因為匯編中的方法不需要有效的this指針。 無論如何,您必須充滿不確定性的舉止。
在fun1
調用delete
后,您對fun2
的調用是非法的。 C ++不會牽手,因此對於這種“未定義的行為”,任何事情都可以發生,包括適當地稱為fun2
。
實際上, delete
調用對象的析構函數,然后釋放內存,與new
相反。
當您調用delete
,操作系統將被告知該內存不再需要,因此可用於將來的分配。 但是,它不會被自動擦除。
就您而言,在調用fun2
之前,其他任何人都不會使用該內存。 沒有人試圖在兩個函數調用之間在堆中分配任何內存。 因此,該對象仍然存在並且從未被篡改。 但是,這並不意味着不可能在兩次調用之間分配內存(例如,可能會觸發中斷,並且在處理中斷期間可能會分配內存)。 因此,您永遠不要這樣做。 :)
當您從類中調用非虛擬函數時,該函數
class A { public: void function(int k) { ... } };
將被寫成類似
void __A_function(A* this, int k);
如果您的函數不包含this
指針,則它將被稱為標准函數,而忽略this
參數。
我可以預測的另一件事是,即使你這樣做
class A
{
private:
int k;
public:
A() : k(10) {}
void function() { printf("%d\n",k); }
};
A* ptr=new A;
delete ptr;
ptr->function();
在大多數情況下,它將打印出10張。 因為來自new
的內存尚未清除。
我將推薦Inside C ++ Object Model來對此進行詳細了解。
成員函數在編譯時解析。
您可以執行以下操作:
A* ptr = NULL;
ptr->yourFunc();
只要您不訪問對象(及其VTable,因此您不想調用方法)中的數據存儲,它將起作用。
'this'的值為null,可以。 但是取消對任何內容的重新配置將導致段錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.