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

Posted

技术标签:

【中文标题】C ++如何在堆栈上动态分配内存?【英文标题】:C++ How to allocate memory dynamically on stack? 【发布时间】:2011-09-14 04:03:45 【问题描述】:

有没有办法在stack而不是堆上分配内存?我找不到这方面的好书,这里有人有想法吗?

【问题讨论】:

如果您想控制 std::string 或 std::vector 分配内存的位置,请检查以下问题:***.com/questions/354442/… @Neil:快速分配/释放临时工作空间? @Neil:如果函数需要少量但可变的临时对象?您可以使用vector,但如果在紧密循环中调用该函数,那么如果可以快速分配和释放内存而不用担心碎片,那就太棒了。 @Andre - 然后在堆栈上分配少量但固定的对象。如果我们不知道上限,alloca 无论如何都会崩溃。 @Alf 我从 2.0 开始就一直在为 Windows 编程,但从未使用过,也从未见过。, 【参考方案1】:

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

例如,如果您有类似的功能

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() 将分配一个额外的 nDataSize 字节每次通过循环。在您从函数返回之前,不会释放 alloca() 字节。因此,如果您的 nDataSize 为 1024,iterations 为 8,您将在返回前分配 8 KB。如果你有一个 nDataSize= 65536 和 iterations = 32768,你将分配总共 65536×32768=2,147,483,648 字节,几乎肯定会炸毁你的堆栈并导致崩溃。

轶事:如果你写超过缓冲区的末尾,你很容易遇到麻烦,特别是如果你将缓冲区传递给另一个函数,并且该子函数对缓冲区的长度有错误的想法。 I once fixed a rather amusing bug 我们使用 alloca() 创建临时存储空间,用于渲染 TrueType 字体字形,然后将其发送到 GPU 内存。我们的字体库在计算字形大小时没有考虑瑞典 Å 字符中的变音符号,所以它告诉我们在渲染之前分配 n 个字节来存储字形,然后实际渲染 n +128 字节。额外的 128 字节写入调用堆栈,覆盖了返回地址并引发了非常痛苦的非确定性崩溃!

【讨论】:

@Neil Butterworth 我们实际上不在嵌入式开发中使用标准 C++ 的众多原因之一。 =P 如果我在递归函数中使用它会怎样?有没有什么副作用?我也不太明白最后一部分,“......如果你在循环中使用它就会爆炸”。但是循环仍然在函数中,对吧? @Mark:如果你在循环中执行 alloca,它会在每次迭代中分配更多内存,但在你从函数返回之前不会释放内存(而像 std::vector local 这样的容器到循环将在循环范围结束时被释放)。 @Mark,你可以在递归循环中使用它。在正常循环中,它不会在函数返回之前释放,因此它可能会产生堆栈溢出,但在递归循环中,它将在每次迭代中被清除。 @Mark :好吧,停下来好好想想。 alloca() 是做什么的,函数的返回类型如何影响它?【参考方案2】:

由于这是标记为 C++,通常您只需在正确的范围内声明所需的对象。它们在堆栈上分配,并保证在范围退出时被释放。这是RAII,是 C++ 优于 C 的一个关键优势。不需要mallocs 或news,尤其是不需要allocas。

【讨论】:

这里的问题是很多C++对象为自己分配内存。 @Zan Lynx - 果然如此。但是,在什么情况下,您会在堆栈上分配这样的对象图? 您可以调用填充向量的函数。你可能需要一个字符串。您可能需要这些东西非常快速且线程安全。如果您不需要这些东西来超越功能,那么堆栈存储就是正确的地方。 @Zan - 对于专门的应用程序,我可以看到这一点。我认为,如果 OP 澄清了为什么需要这样做,我会更容易说服。在大多数情况下,我的观点是不需要。 @Steve - 我主要在嵌入式环境中工作,而且我对堆分配内存的使用经常受到很大限制。【参考方案3】:

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

【讨论】:

如果不是公认的答案,这应该是该特定问题的第二好的答案。与 _alloca 答案不同,它干净简单。 @MarkusL.Clean 简单且错误,因为该问题专门询问动态(非静态)堆栈分配。【参考方案4】:

_malloca。​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

【讨论】:

【参考方案5】:

Article discussing about dynamic memory allocation

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

所以它不需要被显式释放。一个必须记住 这里分配大小,因为可能会发生堆栈溢出异常。堆 溢出异常处理可用于此类调用。的情况下 堆栈溢出异常可以使用_resetstkoflw() 来恢复 返回。

所以我们带有_alloca 的新代码将是:

int NewFunctionA()

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

【讨论】:

欢迎来到 SO!考虑在答案中引用最重要的部分,因为链接可能会失效。 嗨,欢迎来到 SO!通常,仅指向另一个答案的答案不被视为答案。请参阅meta.stackexchange.com/a/118694 了解详情;-) 虽然 alloca 是一种实现方式,但也有一些缺点使其成为不好的做法。请参考这里的讨论; ***.com/a/1018865/83005【参考方案6】:

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

目前,我所知道的最好的方法是通过递归。有各种巧妙的技巧可以做到,但我所知道的最简单的方法是让您的例程声明一个固定大小的数组,然后填充并操作它所拥有的。完成后,如果需要更多空间来完成,它会调用自身。

【讨论】:

你回答了什么问题? 说什么? C++确实允许数组边界的常量值(如果你的意思是数组大小)。 Neil Butterworth - 哈哈,是吗?我是在 VC6 上学习的,所以偶尔会遇到一个不真实的“事实”。因此,您可以例如:将文件中的“数组大小”读入size_t const,然后将其用作数组索引大小? @T.E.D.:不,你不能。如果认为 Neil 理解 static const 你的意思是本地的 const 就像在 void f(const int n) ... 中一样。 @André Caron - 没错。我也不会称其为“显而易见的”。 Ada 允许您毫无顾忌地做这件事。也许在 C++ 中允许这样做是有害的,但从我的角度来看,这似乎是该语言的任意限制。在更改之前,我知道的唯一标准解决方法是将问题模块化并使用递归。【参考方案7】:

您可以使用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

【讨论】:

以上是关于C ++如何在堆栈上动态分配内存?的主要内容,如果未能解决你的问题,请参考以下文章

在C语言中,如何给函数分配内存?

C与C++申请动态内存空间的异同

c语言中啥是动态分配内存?

如何在C中为char**动态分配内存

分配给设备内存的 CUDA 全局(如 C 语言)动态数组

C语言申请内存?