【发布时间】:2012-04-21 07:06:16
【问题描述】:
我正在学习 C++,目前我正在摆弄以下代码:
class Bar;
struct Callback {
virtual void Continue(Bar&) = 0;
};
// ...
void Foo(Bar& _x, Callback& result)
{
// Do stuff with _x
if(/* some condition */) {
// TODO: Force unwind of stack
result.Continue(_x);
return;
}
// Do more stuff with _x
if(/* some other condition */) {
// TODO: Force unwind of stack
result.Continue(_x);
return;
}
// TODO: Force unwind of stack
Bar y; // allocate something on the stack
result.Continue(y);
}
主要思想是我知道在每个站点调用result.Continue 时,函数Foo 也会返回。因此堆栈可以在调用延续之前展开。
由于用户代码将以递归方式使用它,我担心此代码可能会导致堆栈溢出。据我了解,_x 和result 参数在执行result.Continue 时保留在堆栈中,因为只有在Foo 返回时堆栈才会展开。
编辑:Continue 函数可能(并且可能会)调用Foo 方法:导致递归。简单地尾调用优化 Continue 而不是 Foo 可能会导致堆栈溢出。
在Foo 返回之前,我可以做些什么来强制展开堆栈,将result 保留在临时 (register?) 变量中,然后执行该继续?
【问题讨论】:
-
为什么要强制展开堆栈?这对程序的执行流程意味着什么?
-
正如我在问题中解释的那样:
Foo函数可以并且将以递归方式使用。如果函数不强制展开堆栈,则可能导致堆栈溢出。最后一条路径,即没有条件通过,它会分配一些东西,并且可能导致堆栈溢出:但这是因为我分配了一个要在延续中使用的对象。其他执行路径没有。 -
这段代码看起来不常见,但我认为没有任何原因导致堆栈溢出。也许你必须发布更多代码
-
如果那个额外的函数调用(即对
result.continue())导致堆栈溢出,那么你已经遇到了问题! -
一种缓解方法:将 Foo 的局部变量包含在一个虚拟作用域 (
{}) 中,然后在该作用域之外(之后)调用Continue(这闻起来像是可怕的 @987654339 的工作@...):编译器可能注意到现在超出范围的变量的空间可以被回收。我不确定这是在什么优化级别(说到 g++)启用的。-fconserve-stack可能会有所帮助。
标签: c++ stack stack-overflow continuations