为什么在堆栈上分配任意大小的数组是不可能的?

时间:2016-10-11 07:38:46

标签: c++ memory stack heap dynamic-memory-allocation

为什么我不能写以下内容?

char acBuf[nSize];

只是为了防止堆栈过度生长? 或者是否有可能做类似的事情,如果我可以确保我总是只需要几百千字节?

据我所知,std::string使用其成员的内存来存储指定的字符串,只要它们不超过15个字符。只有当字符串更长时,它才会使用这个内存来存储一些堆分配内存的地址,然后获取数据。

在编译时,似乎必须100%确定堆栈在运行时是否对齐。真的吗?那是为什么?

7 个答案:

答案 0 :(得分:1)

与C不同,C ++不支持可变长度数组。如果需要,可以使用非标准扩展,例如alloca或GNU扩展(由clang和GCC支持)。他们有自己的注意事项,因此请务必阅读手册以确保安全使用它们。

堆栈布局主要是静态确定的原因是生成的代码必须执行较少的计算(添加,乘法和指针解除引用)以确定数据在堆栈中的位置。可以将偏移量硬编码到生成的机器代码中。

答案 1 :(得分:1)

它与阻止堆栈溢出无关,你可以使用class Saver(): def __init__(self): self.d = {} def state(self, name): if not name in self.d: return tf.zeros([1,LSTM_SIZE],tf.float32) return self.d[name] def save_state(self, name, val): self.d[name] = val return tf.identity('save_state_name') #<-important for control_dependencies outputs, states = rnn.state_saving_rnn(stacked_lstm, inx, Saver(), ('lstmstate', 'lstmstate2', 'lstmstate3', 'lstmstate4'),sequence_length=[EVAL_SEQ_LEN]) #4 states are for two layers of lstm each has hidden and CEC variables to restore network = [tf.matmul(outputs[-1], W) for i in xrange(EVAL_SEQ_LEN)] 完全溢出堆栈。在C ++中,必须在编译时知道数组大小,这是计算包含数组的结构大小所需的其他内容。

另一方面,从C99开始,C具有可变长度数组,它为函数范围内的数组添加了异常并允许运行时相关的大小。至于为什么C ++没有这个?它从未被C ++标准采用。

答案 2 :(得分:1)

  

为什么我不能写以下内容?

char a[SOME_LARGE_CONSTANT]

这些被称为可变长度数组(VLA&#39; s),并且不受C ++支持。原因是堆栈非常快,但与免费商店(你的话中的堆)相比很小。这意味着在任何时候你向VLA添加了很多元素,你的堆栈可能只是溢出而你得到一个模糊的运行时异常。这也可能发生在编译时大小的堆栈数组中,但这些更容易捕获,因为程序的行为不会影响它们的大小。这意味着在创建堆栈溢出之后,x不会发生,它就在那里。 This更详细地介绍了它。愤怒。

char acBuf[nSize]; 这样的容器使用更大的免费商店,并且有办法处理过度分配(抛出std::vector)。

答案 3 :(得分:0)

我的建议是看看alloca.h

   void *alloca(size_t size);

alloca()函数在堆栈中分配空间的大小字节 呼叫者的框架。此临时空间将自动释放 当调用alloca()的函数返回其调用者时。

答案 4 :(得分:0)

我在C ++中看到的一个可能的问题是类型。

acBufchar acBuf[nSize]的类型是什么类型,char acBuf[nSize][nSize]中更差?

template <typename T> void foo(const T&);

void foo(int n)
{
    char mat[n][n];

    foo(mat);
}

您无法通过引用传递该数组

template <typename T, std::size_t N>
void foo_on_array(const T (&a)[N]);

答案 5 :(得分:0)

你应该感到高兴的是,C ++标准不鼓励危险的做法(堆栈上的可变长度数组),而是鼓励一种不太危险的做法(可变长度数组和带堆分配的std :: vector)。

堆栈上的可变长度数组更危险,因为:

  • 可用堆栈空间通常为8 MB,远小于2 GB(或更多)可用堆空间。
  • 当堆栈空间耗尽时,程序会与SIGSEGV崩溃,并且需要GNU libsigsegv等特殊软件才能从这种情况中恢复。
  • 在典型的C ++程序中,程序员不知道数组长度是否肯定会保持在4 MB的限制之内。

答案 6 :(得分:0)

  

为什么我不能写以下内容? char acBuf[nSize];

你不能这样做,因为在C ++中,必须在编译时知道数组的长度,这是因为编译器为数组保留了指定的内存,并且在运行时不能修改它。它不是要防止堆栈溢出,而是关于内存布局。

如果要创建动态数组,则应使用new运算符,以便将其存储在堆中。

char *acBuf = new char[nsize];