【问题标题】:C++ nested try-catch catching the same exceptions - how should I rewrite this code?C++ 嵌套的 try-catch 捕获相同的异常 - 我应该如何重写这段代码?
【发布时间】:2021-10-18 18:45:07
【问题描述】:

我目前的 C++ 14 代码如下所示:

try {
// create objects, process input
     myObject obj;  // may throw std::invalid_argument in constructor
    
    for (i = 0; i < n_files; i++)
    {
        try {
             process_file(); // may throw std::invalid_argument and std::runtime_error()
         }
         catch (std::exception& e)
          {// print error
              continue;
          }
    }

catch (std::exception& e)
 {// print error
     return 0;
 }

对于我自己的函数,我只是抛出 std::runtime_error 和 std__invalid_exception 之类的 std 异常。

这个想法是,在外部 try 块中创建的对象应该抛出异常并被外部 catch 块捕获,然后结束程序。 process_file() 抛出的异常会被内部的 try 块捕获,它只会打印一些错误但不会导致程序终止,程序将继续处理下一个文件。

外部 try 块包含对象构造函数调用,然后将在内部 try-catch 中使用,因此我不能简单地将其移动到自己的 try-catch 中,否则对象将在循环中未定义。

但是根据我的理解,这段代码不能正常工作,因为在外部 try 块中抛出的异常会首先命中内部 catch 语句,因为这是代码中第一个可到达的 catch 语句。此外,像这样的嵌套 try-catch 会是错误的形式/从我读过的内容中读取会令人困惑。

这样做的正确方法是什么? 谢谢!

【问题讨论】:

    标签: c++ exception c++14


    【解决方案1】:

    根据我的理解,此代码无法正常工作

    是的,对于您描述的场景,它可以正常工作。

    在外部 try 块中抛出的异常将首先命中内部 catch 语句,因为这是代码中第一个可到达的 catch 语句。

    这是不正确的。这与代码中的顺序无关,而与范围中的顺序有关。如果外部try 抛出,则内部try 不在范围内。异常向上调用堆栈,从当前范围开始,然后是最近的外部范围,然后是下一个外部范围,依此类推,直到找到匹配的catch。例如:

    try {
        // if any std exception is thrown here, jumps to A below...
    
        try {
            // if std::invalid_argument is thrown here, jumps to B below...
            // if any other std exception is thrown here, jumps to A below...
    
            for (int i = 0; i < n_files; ++i)
            {
                try {
                    // if any std exception is thrown here, jumps to C below...
                }
                catch (std::exception& e) // C
                {
                    // print error
                    continue;
                }
            }
    
            // if std::invalid_argument is thrown here, jumps to B below...
            // if any other std exception is thrown here, jumps to A below...
        }
        catch (invalid_argument& e) // B
        {
            // print error
            return 0;
        }
    }
    catch (exception& e) // A
    {
        // print error
        return 0;
    }
    

    像这样的嵌套 try-catch 会是错误的形式/从我所读的内容中读取会令人困惑。

    这也不对。使用嵌套的try 块没有任何问题。

    然而,在这个例子中,让内部 try 捕获 ONLY std::invalid_argumentstd::runtime_error 会更有意义,因为它们是它期望和愿意的两种类型忽略以继续循环。不要在那个地方抓到std::exception。这样,如果process_file() 抛出了一些意外(例如std::bad_alloc),那么外部catch 应该处理它以终止进程。

    try {
        // if any std exception is thrown here, jumps to A below...
    
        try {
            // if std::invalid_argument is thrown here, jumps to B below...
            // if any other std exception is thrown here, jumps to A below...
    
            for (int i = 0; i < n_files; ++i)
            {
                try {
                    // if std::invalid_argument is thrown here, jumps to D below...
                    // if std::runtime_error is thrown here, jumps to C below...
                    // if any other std exception is thrown here, jumps to A below...
                }
                catch (std::invalid_argument& e) // D
                {
                    // print error
                    continue;
                }
                catch (std::runtime_error& e) // C
                {
                    // print error
                    continue;
                }
            }
    
            // if std::invalid_argument is thrown here, jumps to B below...
            // if any other std exception is thrown here, jumps to A below...
        }
        catch (invalid_argument& e) // B
        {
            // print error
            return 0;
        }
    }
    catch (exception& e) // A
    {
        // print error
        return 0;
    }
    

    设计catch 的最佳方法是让它只捕获它知道如何在代码中的那个位置处理的特定 类型的异常。让外部catch 处理其他所有事情。如果抛出异常并且没有找到匹配的catch来处理它,则进程将默认终止。

    【讨论】:

      猜你喜欢
      • 2022-01-27
      • 1970-01-01
      • 2013-12-05
      • 1970-01-01
      • 1970-01-01
      • 2012-08-06
      • 1970-01-01
      • 2019-11-11
      • 2015-06-21
      相关资源
      最近更新 更多