为什么需要在编译时知道对象的内存配置文件以进行堆栈放置?

Why does object's memory profile need to be known at compile-time for stack placement?

这似乎是一个广为接受的事实,如果您使用 C++ 等语言实例化对象,则只有在编译时知道对象的大小时,它才有资格进行堆栈放置(而不是堆分配)时间。例如,固定大小的数组可以放在堆栈上,但向量的元素将放在堆上,因为在编译期间最终大小是未知的。

为什么会这样?为什么不能通过移动堆栈指针在运行时动态分配堆栈 space?

编辑:为了清楚起见,这里有一个例子:在一个函数的中间,你计算了一个非常量整数。如果要创建此大小的数组,则必须在堆上进行分配,因为编译时不知道数组的大小。但是为什么不能在创建的时候直接把数组放在栈顶呢?

考虑这段代码:

void extend(std::vector<int>& v, int val) {
    int w = abs(val);
    v.push(w)
}

std::vector<int> v(10);
extend(v, 3);

如果v的内容在栈上,它不会是连续的,因为在v[9]和新压入的v[10]之间还有其他东西。更糟糕的是,如果强制操作,那么 v[10] 几乎肯定会覆盖一些东西。

您可以使用 gcc 的函数 alloca() 和 Microsoft 编译器的函数 _alloca()_malloca() 来完成。

看起来如下:

void allocatesArray(int i)
{
    char *ray = reinterpret_cast<char*>(alloca(i));
    // 'i' bytes of memory allocated, returns void * 

    ray[0] = 'a';
    // space freed, pointer invalidated
}

请注意,这不是一个很好的做法,因为在堆栈溢出的情况下存在未定义的行为。

除非您位于堆栈的最顶部,否则您无法执行的操作是调整大小,因为您无法移动整个堆栈。如果您有一些可能以任何方式改变大小的数据结构,则您不能在当前范围内使用非常量上下文的任何函数调用中使用它。

如果您只是将此视为一种可能的优化方法,clang 已经在适用时进行了所谓的 "heap elision" 以进行此类优化。