避免堆损坏

时间:2012-06-14 15:47:59

标签: c++ memory pointers operating-system heap

今天,在文章heap corruption的EFNet C ++ Wiki上,我找到了两段代码。

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 */  
}    

有人可以帮助我理解为什么第一段代码不被认为是好的吗?

4 个答案:

答案 0 :(得分: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
}  

答案 1 :(得分:2)

当您使用堆栈而不是堆时,一旦当前函数的范围丢失,就会恢复内存。

使用new关键字时,可以分配堆内存。您必须记住删除使用new关键字分配的任何内存。如果在new关键字之后和delete关键字之前抛出异常,则可能会创建内存泄漏,因为您可能无法在抛出异常之后的点恢复执行。

答案 2 :(得分: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

这样,向量中的内存(想想“数组”)就在堆上,但是对象存在并且一些簿记在堆栈上(粗略地说),当对象被破坏时,其堆内存被清除由vector的析构函数自动启动,没有垃圾收集开销等。

这就是所谓的RAII idiom

首选将其放在堆栈上的另一个原因是堆栈上的缓冲区溢出(在处理数组时经常发生)可能比内存在堆上时更具破坏性且更难检测。

答案 3 :(得分:2)

堆是共享内存资源,必须在进程外部进行管理(由内存管理器管理,如示例中所述)。另一方面,堆栈由您的进程管理,并且当您的方法完成时,方法中推送到堆栈的任何变量都会自动释放/弹出。这是干净的,几乎是免费的,几乎是万无一失的。

这避免了创建内存泄漏的可能性 - 其中传递给'delete'的区域(例如,无意中重新分配ptr值)与通过其'new'操作分配的内存不完全匹配。在方法中使用非statish变量时没有理由不这样做。

另见: C++, Free-Store vs Heap