如果我不接受投掷怎么办?

qua*_*ant 20 c++

这是超级基础但我无法在任何地方找到答案.有很多帖子在那里大约抛出和捕获,但实际发生的事情,如果我throwfunction1,然后调用function1function2,但不抓住它,这是否意味着它只是被重新抛出来的来电function2?从以下情况来看,我会说是的,但是在我开始并假设之前,我希望得到一个坚实的大师般的答案:

#include <iostream>

void function1()
{
    throw 1;
}

void function2()
{
    function1();
}

int main()
{
    try
    {
        function2();
    }
    catch(...)
    {
        std::cout << "caught!";
        return 0;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Output: caught!

Ben*_*oit 21

是的,这就是异常的工作方式.抛出异常时,它会被调用堆栈中最顶层的函数捕获,该函数在执行范围内具有该异常的处理程序.由于您将返回堆栈中较低的函数,因此上层堆栈框架中函数范围内的某些变量需要超出范围,因此会调用它们的析构函数.这称为堆栈展开.把它和RAII结合起来真是太好了(如果你不知道那是什么的话,查找RAII).但是,如果任何析构函数在堆栈展开期间抛出异常,则它很糟糕并且std::terminate将调用该函数.通常,您的程序将结束(这就是为什么总是建议您编写非抛出析构函数).

来自cppreference.com:

一旦构造了异常对象,控制流就会向后工作(向上调用堆栈),直到它到达try块的开始,此时将关联的catch块的参数与抛出的表达式进行比较以找到匹配.如果未找到匹配项,则控制流继续展开堆栈直到下一个try块,依此类推.如果找到匹配项,则控制流将跳转到正常执行的匹配catch块(异常处理程序).

当控制流向上移动调用堆栈时,对于所有具有自动存储持续时间的对象调用析构函数,因为以相反的构造顺序输入了相应的try-block.如果从构造函数抛出异常,则会为所有完全构造的非静态非变体成员和基类调用析构函数.此过程称为堆栈展开.


sha*_*oth 10

由于function2()并且function1()没有捕获异常,它将向上传播调用堆栈,直到它被您拥有的第一个合适的处理程序捕获main().沿着被称为堆栈展开的方式调用本地对象析构函数.如果您没有合适的处理程序,C++运行时将调用unexpected()内置函数来调用abort()和终止程序.

  • ...如果没有处理程序,则不需要展开堆栈。我认为它是否是实现定义的,但它可能是未指定的。 (2认同)

Mat*_*lia 7

是的,但它没有得到"重新抛出" - 简单地说,当你抛出一个异常时,它将遍历调用堆栈,直到它找到一个catch可以处理它的块; 这是例外最重要的"卖点"之一.

如果找不到合适的处理程序,std::terminate则调用并且程序异常终止(请注意,在这种情况下,不能保证将调用析构函数).


Mik*_*our 5

这是否意味着它只是被重新抛出给 function2 的调用者?

不,它不会被重新抛出;原件throw根据需要将它发送到调用堆栈的最远位置,直到找到处理程序。在这种情况下,function1or 中没有处理程序function2,因此它最终位于 中的处理程序中main

如果它根本没有被捕获,并试图离开main,那么程序将终止。(有一些方法可以改变这种行为,但这与这个问题并不是特别相关)。