什么是栈展开?搜索了一遍,但没有找到有启发性的答案!
当前回答
每个人都谈论过c++中的异常处理。但是,我认为堆栈展开还有另一个内涵,它与调试有关。调试器必须在应该转到当前帧之前的帧时进行堆栈展开。然而,这是一种虚拟unwind,因为当它回到当前帧时需要倒带。例如gdb中的up/down/bt命令。
其他回答
在我看来,本文中给出的下图漂亮地解释了堆栈unwind对下一条指令路径的影响(一旦抛出未捕获的异常,将执行):
在图片中:
上面一个是正常的调用执行(没有抛出异常)。 当抛出异常时,位于底部。
在第二种情况下,当发生异常时,将在函数调用堆栈中线性搜索异常处理程序。搜索结束于带有异常处理程序的函数,即带有try-catch块的main(),但不是在从函数调用堆栈中删除它之前的所有条目之前。
在Java堆栈中,不宽或不伤人不是很重要(使用垃圾收集器)。在许多异常处理论文中,我看到了这个概念(堆栈展开),特别是那些作者在C或c++中处理异常处理。对于try catch块,我们不应该忘记:在局部块之后释放所有对象的堆栈。
堆栈展开主要是c++的概念,处理当堆栈分配的对象的作用域退出时(正常退出或通过异常退出)如何销毁。
假设你有这样一段代码:
void hw() {
string hello("Hello, ");
string world("world!\n");
cout << hello << world;
} // at this point, "world" is destroyed, followed by "hello"
在一般意义上,堆栈“unwind”几乎等同于函数调用的结束和随后的堆栈弹出。
然而,特别是在c++的情况下,堆栈展开必须与c++如何调用自任何代码块开始分配的对象的析构函数有关。在块中创建的对象将按照其分配的相反顺序被释放。
c++运行时销毁在throw和catch之间创建的所有自动变量。在下面这个简单的例子中,f1()抛出和main()捕获,在B和A类型的对象之间按此顺序在堆栈上创建。当f1()抛出时,将调用B和A的析构函数。
#include <iostream>
using namespace std;
class A
{
public:
~A() { cout << "A's dtor" << endl; }
};
class B
{
public:
~B() { cout << "B's dtor" << endl; }
};
void f1()
{
B b;
throw (100);
}
void f()
{
A a;
f1();
}
int main()
{
try
{
f();
}
catch (int num)
{
cout << "Caught exception: " << num << endl;
}
return 0;
}
这个程序的输出将是
B's dtor
A's dtor
这是因为f1()抛出时程序的调用堆栈看起来像
f1()
f()
main()
因此,当f1()被弹出时,自动变量b被销毁,然后当f()被弹出时,自动变量a被销毁。
希望对大家有所帮助,编码愉快!