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

时间:2013-10-17 14:23:00

标签: c++

这是超级基础,但我无法在任何地方找到答案。有很多关于投掷和捕获的帖子,但是如果throw来自function1,然后从function1调用function2但是没有抓住它,会发生什么?这意味着它只是被function2的调用者重新抛出?从以下情况来看,我会说是的,但是在我开始并假设之前,我希望得到一个坚实的大师般的答案:

#include <iostream>

void function1()
{
    throw 1;
}

void function2()
{
    function1();
}

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

Output: caught!

6 个答案:

答案 0 :(得分:22)

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

来自cppreference.com

  

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

     

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

答案 1 :(得分:10)

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

答案 2 :(得分:7)

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

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

答案 3 :(得分:4)

  

这是否意味着它只是被重新召回到function2的调用者?

不,这不是重生;原始throw在必要时将其发送到调用堆栈,直到找到处理程序。在这种情况下,function1function2中没有处理程序,因此它最终位于main中的处理程序中。

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

答案 4 :(得分:4)

考虑以下计划:

#include <iostream>

void function1()
{
    try
    {
        throw 1;
    }
    catch(...)
    {
        std::cout << "Exception caught in function1." << std::endl;
        throw 1;
    }
}

void function2()
{
    try
    {
        function1();
    }
    catch(...)
    {
        std::cout << "Exception caught in function2." << std::endl;
        throw 1;
    }
}

int main()
{
    try
    {
        function2();
    }
    catch(...)
    {
        std::cout << "Exception caught in main." << std::endl;
    }

    return 0;
}

它的输出是

Exception caught in function1.
Exception caught in function2.
Exception caught in main.

答案 5 :(得分:0)

您可以在没有任何尝试和抓挡的情况下投掷。例如,

std::string &someClass::operator[](unsigned position) {
   // try {
   if (position <= length && position >= 0) {
       //return string at that position;
   }else{
       throw ("out of range");
   }
}

在这种情况下,该函数检查位置是否在动态数组长度之内。否则,它将抛出一个字符串,该字符串将告诉用户他们选择的位置超出范围。因此,有多种方法可以使用不带try and catch块的throw语句(但是try and catch一起使用,不能排除一个)。