函数 try 块是不是允许我们解决异常?

Posted

技术标签:

【中文标题】函数 try 块是不是允许我们解决异常?【英文标题】:Does function try block allows us to resolve a exception?函数 try 块是否允许我们解决异常? 【发布时间】:2020-11-19 08:01:10 【问题描述】:

所以我在link 中阅读了有关函数 try 块的信息。并且有一行描述了普通 try 块和函数 try 块之间的区别,像这样

与允许您解决异常、抛出新异常或重新抛出现有异常的普通 catch 块不同,对于函数级 try 块,您必须抛出或重新抛出异常

但后来我尝试编写一个这样的函数 try 块

#include <iostream> 

int add(int a, int b) try 
    throw 1;
    return a + b;

catch (int) 
    std::cout << "catch in add()";


int main()

    try 
        add(1, 2);
    
    catch (int) 
        std::cout << "catch in main()";
    

输出是

catch in add()

如果函数 try 块不允许我们解决异常,那么 catch in main() 怎么没有被打印出来

【问题讨论】:

某样东西网上C++教程质量普遍偏低。 我在标准中找不到任何说明不允许函数 try 块“解决”异常的内容。 Learncpp 的准确性并不为人所知。 代码正常从add返回,不返回结果(或抛出异常)这是UB。 【参考方案1】:

还有一句话描述了普通try块和函数try块的区别,像这样

那条线是不准确的。 regular 函数的函数 try 块的行为几乎就像它们只是函数的唯一内容一样。意思是,您对add 的定义与

int add(int a, int b) 
    try 
        throw 1;
        return a + b;
    
    catch (int) 
        std::cout << "catch in add()";
    

区别在于构造函数。一方面,函数级别的 try 块是捕获在初始化类成员时引发的异常的唯一方法。

其次,一旦成员初始化抛出异常,构造函数就无法完成,因此对象没有被初始化。在这里,我们不允许简单地吞下例外。如果初始化因抛出异常而失败,则必须将该异常传播或转换为另一种类型并重新抛出。

您链接的页面上的示例在代码中总结了这一点

B(int x) try : A(x) // note addition of try keyword here


catch (...) // note this is at same level of indentation as the function itself

            // Exceptions from member initializer list or constructor body are caught here
 
            std::cerr << "Exception caught\n";
 
            // If an exception isn't explicitly thrown here, the current exception will be implicitly rethrown

【讨论】:

【参考方案2】:

函数 try 块是否允许我们解决异常?

是的。

强制自动抛出仅适用于构造函数和析构函数等少数情况。示例函数既不是构造函数也不是析构函数。

附:该示例的行为未定义,因为它无法从非 void 函数返回值。

【讨论】:

【参考方案3】:

您所遵循的教程部分是错误的。它是这样说的:

最后,与允许您解决异常、抛出新异常或重新抛出现有异常的普通 catch 块不同,使用函数级 try 块,您必须抛出或重新抛出异常。如果你没有显式抛出一个新异常,或者重新抛出当前异常(单独使用 throw 关键字),异常将被隐式地重新抛出堆栈。

就函数而言,这是完全不正确的。

然而,关于构造函数和析构函数,这是真的 C++17 标准是这样说的:

13 如果 return 语句出现在 构造函数的 function-try-block 的处理程序中,则程序格式错误。

14 如果控制到达构造函数或析构函数的函数try-block的处理程序的末尾,则重新抛出当前处理的异常。否则,从复合语句的末尾流出function-try-block 的处理程序等效于从该函数的复合语句的末尾流出。

-- N4713 [except.handle](强调我的)

第 14 点的第一句证实了构造函数和析构函数的这种行为。第二句话直接与您正在遵循的教程中的信息相矛盾,因为他们没有区分这两种情况。


请注意,您的代码会导致未定义的行为,因为函数的 catch 块不会引发异常,也不会返回值,并且函数不会返回 void。您必须从 catch 块中返回一个值以避免 UB。

【讨论】:

以上是关于函数 try 块是不是允许我们解决异常?的主要内容,如果未能解决你的问题,请参考以下文章

Python Try Except

Java异常-可能会出现异常丢失的情况&finally

C++ Primer 5th笔记(chap 18 大型程序工具)函数 try 语句块与构造函数

C#:是不是可以获得异常触发器? [复制]

回调函数解决异步问题-try_caych异步回调判异常

使用Java实现面向对象编程