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