Edd*_*eyo 58
在当前函数返回后不使用变量时使用堆栈.当需要超出当前函数生命周期的变量中的数据时使用堆.
nul*_*Dev 31
根据经验,避免在堆栈上创建大型对象.
Dou*_* T. 13
当正在使用的内存严格限制在您创建它的范围内时,请使用堆栈.这对于避免内存泄漏非常有用,因为您确切知道要使用内存的确切位置,并且知道何时不再需要内存,因此将为您清理内存.
int main()
{
if (...)
{
int i = 0;
}
// I know that i is no longer needed here, so declaring i in the above block
// limits the scope appropriately
}
Run Code Online (Sandbox Code Playgroud)
但是,当您的内存可以在其创建范围之外访问并且您不希望复制堆栈变量时,堆非常有用.这可以让您明确控制内存的分配和释放方式.
Object* CreateObject();
int main()
{
Object* obj = CreateObject();
// I can continue to manipulate object and I decide when I'm done with it
// ..
// I'm done
delete obj;
// .. keep going if you wish
return 0;
}
Object* CreateObject()
{
Object* returnValue = new Object();
// ... do a bunch of stuff to returnValue
return returnValue;
// Note the object created via new here doesn't go away, its passed back using
// a pointer
}
Run Code Online (Sandbox Code Playgroud)
显然,这里的一个常见问题是您可能忘记删除您的对象.这称为内存泄漏.这些问题更为普遍,因为您的程序变得越来越不重要,因为"所有权"(或确切地负责删除事物的人)变得越来越难以定义.
更多托管语言(C#,Java)中的常见解决方案是实现垃圾收集,因此您不必考虑删除内容.但是,这意味着后台有些东西会不定期地运行以检查堆数据.在一个非平凡的程序中,随着"垃圾收集"线程弹出并突然消失,寻找应该删除的数据,而程序的其余部分被阻止执行,这可能变得相当低效.
在C++中,最常见,最好(在我看来)处理内存泄漏的解决方案是使用智能指针.其中最常见的是boost :: shared_ptr,它是(引用计数)
所以重新创建上面的例子boost :: shared_ptr CreateObject();
int main()
{
boost::shared_ptr<Object> obj = CreateObject();
// I can continue to manipulate object and I decide when I'm done with it
// ..
// I'm done, manually delete
obj.reset(NULL);
// .. keep going if you wish
// here, if you forget to delete obj, the shared_ptr's destructor will note
// that if no other shared_ptr's point to this memory
// it will automatically get deleted.
return 0;
}
boost::shared_ptr<Object> CreateObject()
{
boost::shared_ptr<Object> returnValue(new Object());
// ... do a bunch of stuff to returnValue
return returnValue;
// Note the object created via new here doesn't go away, its passed back to
// the receiving shared_ptr, shared_ptr knows that another reference exists
// to this memory, so it shouldn't delete the memory
}
Run Code Online (Sandbox Code Playgroud)
上面提到的规则的一个例外是,您通常应该将堆栈用于函数范围之外不需要的局部变量:
如果递归函数分配大型局部变量或者多次递归调用它们,则递归函数可以耗尽堆栈空间.如果你有一个利用内存的递归函数,那么使用基于堆的内存而不是基于堆栈的内存可能是个好主意.
根据经验,请尽可能使用堆栈。也就是说,在该范围之外永远不需要该变量时。
它的速度更快,可以减少碎片,并且可以避免与调用malloc或new相关的其他开销。从堆栈中分配是几个汇编程序操作,在有效的实现中,malloc或new是几百行代码。
永远不要使用堆...这是不可避免的。:)