1

我似乎有動態內存分配的問題。C++:釋放派生類對象被破壞時的動態內存

下面您會看到一個派生類,其中包含一個名稱變量的指針,該變量將使用void name(const char* name)方法動態分配。該功能由Product構造函數運行,該構造函數在創建對象時爲產品類設置名稱。下面是類:

namespace sict { 
    class Product :public Streamable { 

    char* name_; 

public: 

    Product(const char* name); 
    virtual ~Product(); 

    void name(const char* name); 

} 

而這裏的名稱函數本身,與一個參數的構造函數一起:

void sict::Product::name(const char * name) { 
    int g = strlen(name); 
    name_ = new char[g]; 
    strncpy(name_, name, g); 
    name_[g] = 0; 
} 

Product::~Product() { 
    delete [] name_; 
    name_ = nullptr; 
} 

對我來說這代碼似乎有足夠的能力創建的對象的那麼只要它退出和平摧毀它運行的函數的範圍。但是,當函數結束並且析構函數運行時,程序將在delete [] name_上凍結/崩潰。在Visual Studio的編譯器上運行該程序似乎不會產生特定的錯誤(除了程序凍結),但gcc編譯器檢測到某種堆損壞。有人會知道爲什麼會發生這種情況嗎?

+6

'名_並[g] = 0;'寫入切斷所分配的數組的末尾,損壞堆。嘗試將'g'改爲'strlen(name)+ 1'確認。由於這是C++,你最好使用['std :: string'](http://en.cppreference.com/w/cpp/string/basic_string)並讓它爲你處理內存管理。 –

+3

你不遵守[Rule of 3](http://stackoverflow.com/questions/4172722/what-is-the-rule-of-ree)。 – PaulMcKenzie

+4

哦,這個很簡單,只需使用'std :: string'。你知道,它是C++。不是C. –

回答

3

我不知道爲什麼肖恩克萊恩沒有發表他的評論作爲答案,但肖恩是正確的。

name_給出g元素,然後name_[g]設置爲零,但name_[g]是一個超過數組的末尾。請使用name_ = new char[g+1];name_[g-1] = 0;,以便您不會超出數組的末尾。

而且,有一些評論所指出的,任何時候你有一個動態分配的內存類,請確保您定義的拷貝構造函數,則賦值運算符析構函數。如果您錯過了一個,默認實現將執行一個淺拷貝,這會導致您頭痛。

A 淺拷貝是指針被複制而不是它指向的數據。在你的情況下,如果這個類的一個對象被複制或分配,最終會有兩個對象指向堆上的相同數據,並且它們在運行析構函數時都會嘗試刪除它。

有關的那些功能的更多信息,請參閱Rule of Three