2012-06-14 176 views
4

今天,在EFNet C++ Wiki的文章heap corruption中,我找到了兩段代碼。避免堆腐敗

void this_is_bad() /* You wouldn't believe how often this kind of code can be found */  
{  
    char *p = new char[5]; /* spend some cycles in the memory manager */  
    /* do some stuff with p */  
    delete[] p;  /* spend some more cycles, and create an opportunity for a leak */  
} 

另一種方法:

void this_is_good()  
{  
    /* Avoid allocation of small temporary objects on the heap*/ 
    char p[5]; /* Use the stack instead */ 
    /* do some stuff */ 
}  

有人可以幫助我瞭解爲什麼第一段代碼是沒有考慮好?

+1

誰在第一個片段寫評論的人給我的印象非專業。5個字節的分配通常在堆棧上比在堆上更有意義,並且異常安全性也很好,但是可以通過較少的反駁評論來改善這些觀點(以「*你不會相信*「是一個不好的跡象)。 – asveikau

+0

順便說一下,搜索它看起來不是維基百科,但這個網站的評論:http://www.efnetcpp.org/wiki/Heap_Corruption – asveikau

+0

我的不好,其實我很匆忙。我讀了wiki。 –

回答

7

使用char* p時,您在堆上分配p,因此您必須在最後刪除它。在char *pdelete之間,在do some stuff with p之間,該代碼可能會引發異常並泄漏p

當使用char p[5]時,您將在堆棧上分配p,這樣您不必處理delete,即使代碼拋出異常,您也是安全的。

void this_is_bad() 
{  
    char *p = new char[5]; //on the heap 
    // What happens if I throw an unhandled exception here? 
    delete[] p; // I never get to delete p and it gets leaked 
} 
+2

評論也試圖表達「新」和「刪除」不是免費的操作。而在堆棧上分配數組通常意味着從堆棧指針寄存器中快速減去。 – asveikau

2

當您使用堆棧而不是堆時,一旦當前函數的作用域丟失,內存就會恢復。

當您使用new關鍵字時,您分配堆內存。您必須記得刪除使用new關鍵字分配的內存。如果在new關鍵字之後和delete關鍵字之前拋出異常,則可能會造成內存泄漏,因爲您可能無法在拋出異常之後的位置恢復執行。

2

做到這一點,當前最好的方法是:

#include <vector> 

void this_is_great() 
{ 
    std::vector<char> myCharVec(5); 

    // use myCharVec 

} // when this function ends whether by return or by exception myCharVec is cleaned up 

這種方式在載體中的存儲器(認爲「陣列」)是在堆上,但該對象存在並且一些簿記是在堆棧上(粗略地說),並且當對象被破壞時,它的堆內存會被矢量的析構函數自動清理掉,而沒有垃圾回收開銷等。

這就是所謂的RAII idiom

爲什麼選擇將它放在堆棧上的另一個原因是堆棧上的緩衝區溢出(經常發生在處理數組時)可能比存儲堆棧時更具破壞性和更難檢測。

2

堆是共享內存資源,並且必須從外部管理您的進程(通過內存管理器,如示例中所述)。另一方面,堆棧由您的進程管理,並且在方法完成時,將自動釋放/彈出在您的方法中推入堆棧的所有變量。這是乾淨的,幾乎免費的,並且實際上是防呆的。

這可以避免產生內存泄漏的可能性 - 傳遞給'delete'的區域(例如,通過無意中重新分配ptr值)與通過'new'操作分配的內存不匹配。當在方法內使用非統計變量時,沒有理由做其他事情。

還看到: C++, Free-Store vs Heap