这是超级基础,但我无法在任何地方找到答案。有很多关于投掷和捕获的帖子,但是如果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!
答案 0 :(得分:22)
是的,这就是异常的工作方式。抛出异常时,它会被调用堆栈中最顶层的函数捕获,该函数在执行范围内具有该异常的处理程序。由于您将返回堆栈中较低的函数,因此上层堆栈框架中函数范围内的某些变量需要超出范围,因此会调用它们的析构函数。这称为堆栈展开。把它和RAII结合起来真是太好了(如果你不知道那是什么的话,查找RAII)。但是,如果任何析构函数在堆栈展开期间抛出异常,那么它很糟糕并且将调用std::terminate
函数。通常,您的程序将结束(这就是为什么总是建议您编写非抛出析构函数)。
一旦构造了异常对象,控制流就会起作用 向后(向上调用堆栈),直到它到达尝试的开始 块,此时关联的catch块的参数 与抛出的表达式进行比较以找到匹配项。如果不匹配 找到后,控制流程继续展开堆栈直到 接下来尝试阻止,依此类推。如果找到匹配,则控制流跳转 到执行的匹配catch块(异常处理程序) 通常
当控制流向上移动调用堆栈时,将调用析构函数 对于所有具有自动存储持续时间的对象 以相反的构造顺序输入相应的try-block。 如果从构造函数抛出异常,则调用析构函数 适用于所有完全构造的非静态非变体成员和基础 类。此过程称为堆栈展开。
答案 1 :(得分:10)
由于function2()
和function1()
没有捕获异常,它将传播向上调用堆栈,直到它被{{中的第一个合适的处理程序捕获“ 1}}。沿着称为堆栈展开的方式调用本地对象析构函数。如果您没有合适的处理程序,C ++运行时将调用main()
内置函数,该函数将调用unexpected()
并终止该程序。
答案 2 :(得分:7)
是的,但它没有“重新抛出” - 简单地说,当你抛出一个异常时,它将遍历调用堆栈,直到它找到一个可以处理它的catch
块;这是例外中最重要的“卖点”之一。
如果找不到合适的处理程序,则调用std::terminate
并且程序异常终止(请注意,在这种情况下,不能保证将调用析构函数)。
答案 3 :(得分:4)
这是否意味着它只是被重新召回到function2的调用者?
不,这不是重生;原始throw
在必要时将其发送到调用堆栈,直到找到处理程序。在这种情况下,function1
或function2
中没有处理程序,因此它最终位于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一起使用,不能排除一个)。