簡體   English   中英

了解C ++中的刪除運算符

[英]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 newconstructordelete操作是否相似?

謝謝

您正在做的是技術上未定義的行為,因此,實際上,就標准而言,任何事情都可能發生。

除此之外,您所看到的實際行為可以輕松推斷。 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM