C++如何在堆栈上动态分配内存

C++ How to allocate memory dynamically on stack?

本文关键字:动态分配 内存 堆栈 C++      更新时间:2023-10-16

有没有办法在堆栈而不是堆上分配内存?我找不到一本关于这方面的好书,这里有人知道吗?

使用alloca()(有时也称为_alloca()_malloca()),但要非常小心—当你离开一个函数时,它会释放内存,而不是当你超出范围时,所以如果你在循环中使用它,你会很快崩溃。

例如,如果你有一个类似的功能

int foo( int nDataSize, int iterations ) 
{
   for ( int i = 0; i < iterations ; ++i )
   {
      char *bytes = alloca( nDataSize );
      // the memory above IS NOT FREED when we pass the brace below!
   } 
   return 0;
}  // alloca() memory only gets freed here

然后alloca()将在每次循环时分配额外的数据大小字节。在从函数返回之前,不会释放任何alloca()字节。因此,如果nDataSize为1024,iterations为8,那么在返回之前将分配8千字节。如果您的nDataSize=65536和iterations=32768,那么您将总共分配65536×32768=2147483648字节,几乎可以肯定会破坏堆栈并导致崩溃。

轶事:如果您在缓冲区结束后写入,特别是如果您将缓冲区传递给另一个函数,并且该子函数对缓冲区的长度有错误的想法,那么您很容易遇到麻烦。我曾经修复了一个相当有趣的错误,我们使用alloca()创建临时存储,用于在将TrueType字体字形发送到GPU内存之前渲染它。我们的字体库没有考虑瑞典语中的变音符号Å字符,所以它告诉我们在渲染之前分配n字节来存储字形,然后实际渲染n+128字节。额外的128字节写入了调用堆栈,覆盖了返回地址,并引发了一场非常痛苦的不确定崩溃!

由于这是标记为C++的,通常您只需在正确的范围内声明所需的对象。它们在堆栈上分配,并保证在作用域退出时释放。这就是RAII,也是C++相对于C的一个关键优势。不需要malloc s或new s,尤其是不需要alloca s。

您可以声明一个本地char[1024]或任何您想要的字节数(最多一点),然后取本地地址作为指向堆栈上该内存块的指针。不完全是动态的,但如果需要,您可以使用自己的内存管理器来封装这些内存。

讨论动态内存分配的文章

我们可以通过以下方式在堆栈内存上动态分配可变长度空间使用函数_alloca。此函数从程序堆栈中分配内存。它只需占用要分配的字节数,并将void*返回给正如malloc调用一样分配了空间。此分配的内存将在函数退出时自动释放。

因此,不需要明确地释放它。一个人必须牢记此处的分配大小,因为可能会发生堆栈溢出异常。堆栈溢出异常处理可用于此类调用。如果堆栈溢出异常可以使用_resetstkoflw()进行恢复返回

因此,我们使用_alloca的新代码将是:

int NewFunctionA()
{
   char* pszLineBuffer = (char*) _alloca(1024*sizeof(char));
    …..
  // Program logic
     ….
  //no need to free szLineBuffer
  return 1;
}

参见_malloca。​​​​​​​​​​​​​​​ ​

当/如果C++允许使用(非静态)const值作为数组边界时,会更容易。

目前,我所知道的最好的方法是通过递归。有各种各样的聪明技巧可以做到,但据我所知,最简单的方法是让你的例程声明一个固定大小的数组,并填充和操作它所拥有的。当它完成时,如果它需要更多的空间来完成,它就会自称。

您可以使用BDE C++库,例如

const int BUFFER_SIZE = 1024;
char      buffer[BUFFER_SIZE];
bdlma::BufferedSequentialAllocator allocator(buffer, BUFFER_SIZE);
bsl::vector<int>                   dataVector(&allocator);
dataVector.resize(50);

BDE提供了全面的分配器选项以及bsl::vector等集合,这些集合可以在不更改容器类型的情况下使用多态分配器。

您也可以考虑:

  • https://github.com/facebook/folly/blob/master/folly/docs/small_vector.md
  • http://www.boost.org/doc/libs/1_55_0/doc/html/container/non_standard_containers.html#container.non_standard_containers.static_vector
  • http://llvm.org/docs/doxygen/html/classllvm_1_1SmallVector.html