簡體   English   中英

析構函數不會破壞對象

[英]Destructor does not destroy objects

我已經編寫了一個小程序,但是主析構函數無法正常工作。 這是程序的代碼:

#include<iostream.h>

class citizen {
private:
    char* name;
    char* nationality;
public:             
    citizen(char* name, char* nationality) {
        this->name = name;
        this->nationality = nationality;
    }                  

    citizen(const citizen &obj) {
        name = obj.name;
        nationality = obj.nationality;
    }        

    void display() {
        cout << "Name: " << name << endl;
        cout << "Nationality: " << nationality << endl;
    }

    ~citizen() { 
        if(name){
            delete[]name;
        }
        if(nationality) {
            delete []nationality;                          
        }        
    }       
};

main() {
   citizen obj1("Ali", "Pakistani");
   obj1.display();
   { 
      citizen obj2 = obj1;                 
   }
   obj1.display();
   system("pause");
}

我所知道的是,在將obj1狀態分配給obj2 main函數中,這兩個位置現在都指向相同的內存區域。 而代碼citizen obj2 = obj1; 在兩個花括號之間。

   { 
      citizen obj2 = obj1;                 
   }

因此,在執行第二個花括號后, obj2應該銷毀並刪除變量namenationality 當我調用obj1.display(); 第二次它應該在屏幕上顯示垃圾。

但是obj1仍在打印我在構造函數中提供的確切名稱,即使它不是應該如此。

請解釋此行為。

您的delete[]調用未定義的行為,因為您正試圖破壞字符串文字。 什么都可能發生。

即使您自己分配了內存,您仍然會遇到未定義的行為,因為您將嘗試訪問已刪除的內存:

obj1.display();
{ 
   citizen obj2 = obj1;                 
}
obj1.display();  // ILLEGAL

因為您沒有定義賦值運算符,所以將使用編譯器生成的賦值運算符,它僅將指針分配給相同的內存-您先銷毀然后嘗試訪問的內存。

復制構造函數只復制指針(如果沒有提供自己的指針,則隱式指針會這樣做),這意味着兩個對象都將嘗試刪除相同的數組。 另外,您正在將指針設置為指向字符串文字,這些文字絕對不能刪除。 您只能刪除使用new創建的對象。 一個簡單的解決方案是將內存管理委托給一個旨在正確執行此操作的類:

std::string name;
std::string nationality;

現在,您無需費心使用自己的析構函數,復制構造函數或復制分配運算符; 另外,您的課程也可以在C ++ 11中正確移動。

如果您喜歡自己處理內存問題,則需要構造函數分配新的緩沖區並在其中復制內容。 請謹慎對待異常安全性,因為您試圖在一個類中處理兩個單獨的動態資源,而這總是錯誤的根源。 您還需要一個拷貝分配運算符(按照3的規則 ),為了提高效率,您還可以考慮一個move構造函數和move-assignment運算符。

同樣,可能值得更新到本世紀的一種語言版本。 <iostream.h>大約十五年來一直不是標准頭文件。

該代碼有誤。

     if(name){
              delete[]name;
     }
     if(nationality){                          
              delete []nationality;                          
     }   

您正在使用new運算符刪除尚未在堆上分配的內容。

也有人指出,該字符串相關的錯誤,但我認為你正在做一個更根本的錯誤: delete 破壞的東西。*; 它只是釋放內存以供重用,並調用相關的析構函數。 這意味着在delete操作之后通常完全有可能使用刪除的對象,而不會導致垃圾回收。

*-在某些實現中,在__DEBUG模式下,它將在釋放的內存上加蓋戳記,以允許您發現這些錯誤,但這不是標准的一部分。

您應該只delete使用new operator在類中dynamically allocated的內存塊

citizen(char* aname, char* anationality){

     size_t nameSize = strlen(aname)
     size_t nationalitySize = strlen(anationality)

     this->name = new char[nameSize];
     this->nationality = new char[nationalitySize];

     strcpy(this->name, aname, nameSize);
     this->name[nameSize ] = NULL;

     strcpy(this->nationality , anationality , nationalitySize);
     this->nationality [nationalitySize] = NULL;
}

如果在constructor創建內存,則在destructor中將其刪除。 並且由於您有一些分配,那么您應該實現一個copy constructor ,WHICH創建一個內存並在= operator的右側復制數據

最后的想法是,如果不能處理指針以避免memory leaks ,最好使用字符串對象

很高興您的第二次展示電話可以正常工作。

正如Jack Aidley指出的那樣,delete並不從字面上刪除值,只是將內存區域標記為可用。 因此,如果沒有其他應用程序分配和修改該釋放區域,則先前的值可能會保留在那里。 此外,刪除后,您仍然保留指向該地址的指針。

總而言之,您正在訪問具有舊值的相同內存區域。 但這很幸運,因為該區域未被任何人修改。

為防止此類錯誤,應始終將NULL分配給未使用的指針,以便下次嘗試訪問它們時遇到訪問沖突錯誤。 一些編譯器(例如MSVC)用簽名值(例如0xDDDDDD)重寫釋放的內存,以便在調試過程中可以輕松地發現問題。 查看此答案以獲取詳細信息

最后, delete應該與new匹配,否則行為是不確定的,因此再次很幸運。 我什至無法運行您的應用程序並顯示結果。 它不斷崩潰,並給出內存錯誤。

謝謝大家。 我已替換此構造函數代碼

citizen(char* name, char* nationality) {
    this->name = name;
    this->nationality = nationality;
}        

用這個代碼

citizen(char* name, char* nationality){ 
   this->name = new char[strlen(name)+1]; 
   strcpy(this->name, name); 
   this->nationality = new char[strlen(nationality)+1]; 
    strcpy(this->nationality, nationality); 
} 

最終效果很好。 謝謝

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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