今天,在文章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 */
}
有人可以帮助我理解为什么第一段代码不被认为是好的吗?
答案 0 :(得分:7)
使用char* p
时,您在堆上分配p
,因此您必须在最后处理它。在char *p
和delete
之间,在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变量时没有理由不这样做。