堆栈溢出:在堆栈空间中复制临时分配?
struct MemBlock {
char mem[1024];
MemBlock operator*(const MemBlock &b) const {
return MemBlock();
}
} global;
void foo(int step = 0) {
if (step == 10000)
{
global = global * MemBlock();
}
else foo(step + 1);
}
int main() {
foo();
return 0;
}
程序接收到的信号SIGSEGV,分段故障。 0x08048510在FOO在t.cpp(步骤= 4000):12 12无效美孚(INT步骤= 0){堆栈溢出:在堆栈空间中复制临时分配?
看来,MemBlock()实例费了很多堆栈存储器的虽然它不是招”尚未被调用(检查gdb信息)。
而当我使用global = global * global
代替时,程序正常退出。
任何人都可以解释内部机制吗?
无论foo
中的控制流程如何,每次调用foo
时,编译器都会为MemBlock
实例保留堆栈空间。这是一种常见的优化措施,可以防止在函数内重复调整堆栈指针。相反,编译器会计算所需的最大堆栈空间,并在该函数的入口处按该量调整堆栈指针。
正如你所观察到的,这会导致为实际上没有使用的对象保留堆栈空间。答案是不这样做;如果你只在某些分支中使用一些大尺寸的对象,那么将这些分支分离出它们自己的功能。顺便说一下,这就是为什么古老版本的C需要在函数顶部声明所有函数范围变量的原因;以便编译器可以轻松计算出该函数需要多少堆栈空间。
我喜欢最后的历史课,我不知道那个小知识:) – 2012-07-20 12:53:02
我试图用'MemBlock * t = new MemBlock; global = global * * t;'我认为它会在运行时构建,并且不会影响堆栈空间。但仍然是错误。有什么问题? – Determinant 2012-07-20 13:11:37
+1 for *“如果你只是在某些分支中使用一些大尺寸的对象,然后将这些分支分离出它们自己的函数。”* .. **和** *“顺便说一句,这就是为什么古老版本的C需要在函数顶部声明所有函数范围变量;以便编译器可以轻松计算出函数需要多少堆栈空间“* – Nawaz 2012-07-20 13:15:14
您收到段错误,因为您递归调用foo 10000次,它与MemBlock类 – 2012-07-20 12:23:40
@TomKnapen无关,不,您错了。 a)它在4001对我的要求中死亡。 b)如果你删除'if'里面的东西,它根本不会死。 – SingerOfTheFall 2012-07-20 12:25:05
@SingerOfTheFall我的评论可能是更好的时候,它试图“调用富10000次”,但问题仍然存在:这是递归的错。如果你删除了if块,编译器可能会优化函数调用,从而消除递归。 – 2012-07-20 12:27:21