Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ember.js/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
什么时候最好使用堆栈而不是堆,反之亦然? 在C++中,什么时候最好使用栈?何时最好使用堆?_C++ - Fatal编程技术网

什么时候最好使用堆栈而不是堆,反之亦然? 在C++中,什么时候最好使用栈?何时最好使用堆?

什么时候最好使用堆栈而不是堆,反之亦然? 在C++中,什么时候最好使用栈?何时最好使用堆?,c++,C++,在运行时使用堆仅为对象分配空间。如果在编译时知道大小,请使用堆栈。不要从函数返回堆分配的对象,而是将缓冲区传递到函数中,以便写入。这样,可以在函数被称为数组或其他基于堆栈的结构的地方分配缓冲区 malloc()语句越少,内存泄漏的可能性就越小 当当前函数返回后变量将不被使用时,请使用堆栈。当变量中的数据在当前函数的生命周期之外需要时,请使用堆。此问题与前几天提出的问题有关(尽管不是真正的重复)。此问题的格式不正确 有些情况下需要堆栈,有些情况下需要堆,有些情况下需要静态存储,有些情况下需要常量内

在运行时使用堆仅为对象分配空间。如果在编译时知道大小,请使用堆栈。不要从函数返回堆分配的对象,而是将缓冲区传递到函数中,以便写入。这样,可以在函数被称为数组或其他基于堆栈的结构的地方分配缓冲区


malloc()语句越少,内存泄漏的可能性就越小

当当前函数返回后变量将不被使用时,请使用堆栈。当变量中的数据在当前函数的生命周期之外需要时,请使用堆。

此问题与前几天提出的问题有关(尽管不是真正的重复)。

此问题的格式不正确

有些情况下需要堆栈,有些情况下需要堆,有些情况下需要静态存储,有些情况下需要常量内存数据,有些情况下需要空闲存储


堆栈速度很快,因为分配只是SP上的一个“增量”,所有的“分配”都是在所处函数的调用时执行的。堆(或免费存储)分配/释放的时间开销更大,也更容易出错。

根据经验,避免在堆栈上创建大型对象

  • 在堆栈上创建一个对象可以使您从记忆清理(读取或删除)对象的负担中解脱出来。但是在堆栈上创建过多的对象会增加堆栈溢出的可能性
  • 如果您对对象使用heap,您将获得操作系统所能提供的内存,比堆栈大得多,但是您必须再次确保在完成时释放内存。此外,在堆中过于频繁地创建太多对象会导致内存碎片化,进而影响应用程序的性能

当所使用的内存严格限制在创建堆栈的范围内时,请使用堆栈。这对于避免内存泄漏非常有用,因为您确切地知道要在哪里使用内存,并且知道何时不再需要它,因此内存将为您清理

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
}
但是,当您的内存可能在其创建范围之外被访问,并且您不希望复制堆栈变量时,堆非常有用。这可以让您明确控制内存的分配和释放方式

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
}
显然,这里的一个常见问题是您可能会忘记删除对象。这称为内存泄漏。当您的程序变得越来越不重要时,这些问题就越来越普遍,因为“所有权”(或者谁确切负责删除内容)变得越来越难以定义

在更受管理的语言(C#,Java)中,常见的解决方案是实现垃圾收集,这样您就不必考虑删除内容。然而,这意味着后台有一些东西不定期地运行以检查堆数据。在一个非平凡的程序中,当一个“垃圾收集”线程弹出并突然离开,寻找应该删除的数据,而程序的其余部分被阻止执行时,这可能会变得相当低效

C++中最常见、最好的(我认为)解决内存泄漏的方法是使用智能指针。其中最常见的是()

因此,重新创建上面的示例 boost::shared_ptr CreateObject()

intmain()
{
boost::shared_ptr obj=CreateObject();
//我可以继续操纵对象,并决定何时完成操作
// ..
//我完成了,手动删除
对象重置(空);
//如果你愿意,继续走
//在这里,如果您忘记删除obj,共享的ptr的析构函数会注意到
//如果没有其他共享内存指向此内存
//它将自动被删除。
返回0;
}
boost::shared_ptr CreateObject()
{
boost::shared_ptr returnValue(new Object());
//…做一大堆事来回报价值
返回值;
//注意,通过newhere创建的对象不会消失,它会传递回
//接收共享\u ptr、共享\u ptr知道存在另一个引用
//到这个内存,所以它不应该删除内存
}

根据经验,尽可能使用堆栈。i、 e.当变量从未超出该范围时

它的速度更快,导致更少的碎片,并将避免与调用malloc或new相关的其他开销。在一个高效的实现中,从堆栈外分配代码只需几个汇编程序操作,malloc或new则需要几百行代码


使用堆从来都不是最好的。。。只是不可避免的。:)

上述规则的一个例外,您通常应将堆栈用于函数范围之外不需要的局部变量:


如果递归函数分配较大的局部变量,或者递归调用多次,则会耗尽堆栈空间。如果您有一个使用内存的递归函数,那么使用基于堆的内存而不是基于堆栈的内存可能是一个好主意。

不过有一些方法可以解决这个问题。向函数传递一个缓冲区,然后将数据写入该缓冲区是让函数“返回”位于较低堆栈帧中的动态数据的一种好方法。它不像OO,但效率更高。大小也是一个考虑因素:堆栈上超过1K的任何内容都应该仔细考虑。有时最好有一个指向堆内存的堆栈指针(以及“资源获取就是初始化”的习惯用法),但是当内存是类的属性时,如何确定类属性何时应该是指针呢?另外,您什么时候可以使用智能指针?在2020年,我想指出,这不再是好的做法:因为移动和复制省略语义,传递局部变量
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
}