堆栈溢出:在堆栈空间中复制临时分配?

问题描述:

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代替时,程序正常退出。

任何人都可以解释内部机制吗?

+1

您收到段错误,因为您递归调用foo 10000次,它与MemBlock类 – 2012-07-20 12:23:40

+0

@TomKnapen无关,不,您错了。 a)它在4001对我的要求中死亡。 b)如果你删除'if'里面的东西,它根本不会死。 – SingerOfTheFall 2012-07-20 12:25:05

+3

@SingerOfTheFall我的评论可能是更好的时候,它试图“调用富10000次”,但问题仍然存在:这是递归的错。如果你删除了if块,编译器可能会优化函数调用,从而消除递归。 – 2012-07-20 12:27:21

无论foo中的控制流程如何,每次调用foo时,编译器都会为MemBlock实例保留堆栈空间。这是一种常见的优化措施,可以防止在函数内重复调整堆栈指针。相反,编译器会计算所需的最大堆栈空间,并在该函数的入口处按该量调整堆栈指针。

正如你所观察到的,这会导致为实际上没有使用的对象保留堆栈空间。答案是不这样做;如果你只在某些分支中使用一些大尺寸的对象,那么将这些分支分离出它们自己的功能。顺便说一下,这就是为什么古老版本的C需要在函数顶部声明所有函数范围变量的原因;以便编译器可以轻松计算出该函数需要多少堆栈空间。

+0

我喜欢最后的历史课,我不知道那个小知识:) – 2012-07-20 12:53:02

+0

我试图用'MemBlock * t = new MemBlock; global = global * * t;'我认为它会在运行时构建,并且不会影响堆栈空间。但仍然是错误。有什么问题? – Determinant 2012-07-20 13:11:37

+0

+1 for *“如果你只是在某些分支中使用一些大尺寸的对象,然后将这些分支分离出它们自己的函数。”* .. **和** *“顺便说一句,这就是为什么古老版本的C需要在函数顶部声明所有函数范围变量;以便编译器可以轻松计算出函数需要多少堆栈空间“* – Nawaz 2012-07-20 13:15:14