我对C ++异常处理机制的工作方式很感兴趣。具体来说,异常对象存储在哪里,如何在多个作用域内传播,直到被捕获?它存储在某个全局区域中吗?
由于这可能是特定于编译器的,因此有人可以在g ++编译器套件的上下文中对此进行解释吗?
Answers:
实现可能有所不同,但是从需求中可以得出一些基本思想。
异常对象本身是在一个函数中创建的对象,在其调用者中销毁了该对象。因此,在堆栈上创建对象通常是不可行的。另一方面,许多异常对象不是很大。因此,如果实际上需要一个更大的异常对象,则可以创建一个32字节的缓冲区并溢出到堆。
关于控制的实际转移,存在两种策略。一种是在堆栈本身中记录足够的信息以展开堆栈。这基本上是要运行的析构函数和可能捕获异常的异常处理程序的列表。如果发生异常,请运行执行那些析构函数的堆栈,直到找到匹配的catch。
第二种策略将这些信息移到堆栈外部的表中。现在,当发生异常时,将使用调用堆栈来确定已输入但未退出的范围。然后在静态表中查找这些值,以确定将在何处处理引发的异常以及在它们之间运行哪些析构函数。这意味着堆栈上的异常开销更少。无论如何都需要返回地址。这些表是多余的数据,但是编译器可以将它们放在程序的按需加载的段中。
free()
或fclose()
在一些很少使用的代码路径。
在15.1抛出标准例外中定义。
抛出将创建一个临时对象。
未指定此临时对象的内存分配方式。
创建临时对象后,控件将传递给调用堆栈中最接近的处理程序。解开掷点和接球点之间的堆栈。随着堆栈展开,所有堆栈变量都以相反的创建顺序销毁。
除非重新抛出异常,否则临时文件将在被捕获的处理程序结尾处销毁。
注意:如果按引用捕获,则引用将引用临时对象;如果按值捕获,则将临时对象复制到值中(因此需要复制构造函数)。
来自S.Meyers的建议(按const引用进行捕获)。
try
{
// do stuff
}
catch(MyException const& x)
{
}
catch(std::exception const& x)
{
}
您可以在这里查看详细说明。
看看普通C语言中用来实现一些基本类型的异常处理的技巧也可能会有所帮助。这需要以以下方式使用setjmp()和longjmp():前者保存堆栈以标记异常处理程序(如“ catch”),而后者用于“抛出”值。视为“已抛出”值,就好像它是从已调用函数返回的一样。当再次调用setjmp()或函数返回时,“ try块”结束。
我知道这是一个老问题,但是有一个很好的阐述,在这里解释了gcc和VC中使用的两种方法:http : //www.hexblog.com/wp-content/uploads/2012/06/Recon- 2012-Skochinsky-Compiler-Internals.pdf