什么是栈展开?搜索了一遍,但没有找到有启发性的答案!
当前回答
堆栈展开通常与异常处理有关。这里有一个例子:
void func( int x )
{
char* pleak = new char[1024]; // might be lost => memory leak
std::string s( "hello world" ); // will be properly destructed
if ( x ) throw std::runtime_error( "boom" );
delete [] pleak; // will only get here if x == 0. if x!=0, throw exception
}
int main()
{
try
{
func( 10 );
}
catch ( const std::exception& e )
{
return 1;
}
return 0;
}
在这里,如果抛出异常,分配给pleak的内存将丢失,而分配给s的内存将在任何情况下通过std::string析构函数正确释放。当退出作用域时,在堆栈上分配的对象将被“解开”(这里的作用域是函数func的作用域)。这是通过编译器插入对自动(堆栈)变量析构函数的调用来完成的。
现在,这是一个非常强大的概念,导致称为RAII的技术,即资源获取即初始化,它帮助我们在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被销毁。
希望对大家有所帮助,编码愉快!
我不知道你是否读过这篇文章,但维基百科关于调用堆栈的文章有一个很好的解释。
解除:
Returning from the called function will pop the top frame off of the stack, perhaps leaving a return value. The more general act of popping one or more frames off the stack to resume execution elsewhere in the program is called stack unwinding and must be performed when non-local control structures are used, such as those used for exception handling. In this case, the stack frame of a function contains one or more entries specifying exception handlers. When an exception is thrown, the stack is unwound until a handler is found that is prepared to handle (catch) the type of the thrown exception. Some languages have other control structures that require general unwinding. Pascal allows a global goto statement to transfer control out of a nested function and into a previously invoked outer function. This operation requires the stack to be unwound, removing as many stack frames as necessary to restore the proper context to transfer control to the target statement within the enclosing outer function. Similarly, C has the setjmp and longjmp functions that act as non-local gotos. Common Lisp allows control of what happens when the stack is unwound by using the unwind-protect special operator. When applying a continuation, the stack is (logically) unwound and then rewound with the stack of the continuation. This is not the only way to implement continuations; for example, using multiple, explicit stacks, application of a continuation can simply activate its stack and wind a value to be passed. The Scheme programming language allows arbitrary thunks to be executed in specified points on "unwinding" or "rewinding" of the control stack when a continuation is invoked.
检查[编辑]
堆栈展开通常与异常处理有关。这里有一个例子:
void func( int x )
{
char* pleak = new char[1024]; // might be lost => memory leak
std::string s( "hello world" ); // will be properly destructed
if ( x ) throw std::runtime_error( "boom" );
delete [] pleak; // will only get here if x == 0. if x!=0, throw exception
}
int main()
{
try
{
func( 10 );
}
catch ( const std::exception& e )
{
return 1;
}
return 0;
}
在这里,如果抛出异常,分配给pleak的内存将丢失,而分配给s的内存将在任何情况下通过std::string析构函数正确释放。当退出作用域时,在堆栈上分配的对象将被“解开”(这里的作用域是函数func的作用域)。这是通过编译器插入对自动(堆栈)变量析构函数的调用来完成的。
现在,这是一个非常强大的概念,导致称为RAII的技术,即资源获取即初始化,它帮助我们在c++中管理内存、数据库连接、打开的文件描述符等资源。
现在这允许我们提供异常安全保证。
每个人都谈论过c++中的异常处理。但是,我认为堆栈展开还有另一个内涵,它与调试有关。调试器必须在应该转到当前帧之前的帧时进行堆栈展开。然而,这是一种虚拟unwind,因为当它回到当前帧时需要倒带。例如gdb中的up/down/bt命令。
在Java堆栈中,不宽或不伤人不是很重要(使用垃圾收集器)。在许多异常处理论文中,我看到了这个概念(堆栈展开),特别是那些作者在C或c++中处理异常处理。对于try catch块,我们不应该忘记:在局部块之后释放所有对象的堆栈。
推荐文章
- 为什么我的程序不能在Windows 7下用法语编译?
- 如何获取变量的类型?
- 什么是奇怪的重复模板模式(CRTP)?
- 连接两个向量的最佳方法是什么?
- 在c++中,是通过值传递更好,还是通过引用到const传递更好?
- 在STL中deque到底是什么?
- Windows上最好的免费c++分析器是什么?
- 如何自动转换强类型枚举为int?
- 在一个类中使用具有成员函数的泛型std::function对象
- 'for'循环中的后增量和前增量产生相同的输出
- 虚函数和纯虚函数的区别
- c++中的_tmain()和main()有什么区别?
- 内存泄漏是否正常?
- 当启用c++ 11时,std::vector性能回归
- 什么时候使用哪种指针?