【问题标题】:C++ get description of an exception caught in catch(...) blockC++ 获取在 catch(...) 块中捕获的异常的描述
【发布时间】:2011-04-08 04:34:27
【问题描述】:

我可以得到一个被捕获的异常的描述

catch(...)

阻止?类似于 std::exception 的 .what()。

【问题讨论】:

标签: c++ exception try-catch


【解决方案1】:

你可以使用一个技巧:

catch(...) {
    handle_exception();
}

void handle_exception() {
    try {
        throw;
    } catch (const std::exception &e) {
        std::cout << e.what() << "\n";
    } catch (const int i) {
        std::cout << i << "\n";
    } catch (const long l) {
        std::cout << l << "\n";
    } catch (const char *p) {
        std::cout << p << "\n";
    } catch (...) {
        std::cout << "nope, sorry, I really have no clue what that is\n";
    }

等等,你认为可能会抛出尽可能多的不同类型。如果您真的对可能抛出的内容一无所知,那么即使倒数第二个也是错误的,因为有人可能会抛出一个不指向以 nul 结尾的字符串的char*。

抛出任何不是std::exception 或派生类的东西通常是个坏主意。 std::exception 存在的原因是允许每个人投掷和捕捉他们可以做一些有用的事情的对象。在一个玩具程序中,您只想离开那里,甚至懒得包含标准标题,好吧,也许抛出一个int 或字符串文字。我认为我不会将其作为正式界面的一部分。您抛出的任何异常都是正式界面的一部分,即使您不知何故忘记记录它们。

【讨论】:

  • 嗨;这是一个很好的答案。我一直在寻找一些时间来在标准文件中找到证明这是标准行为的证据,但一直找不到任何证据。您确定这是标准行为吗? (也就是说,在catch(...){} 中输入新的try-block 并重新抛出异常以确定其类型。)
  • 从内存中工作:查找有关当前异常的生命周期的文本(直到您退出 catch 子句),以及没有操作数的 throw 的效果(重新抛出当前异常)。
【解决方案2】:

该块可能会捕获一个 int、一个 const char* 或任何东西。当编译器对它一无所知时,它怎么可能知道如何描述它呢?如果你想从异常中获取信息,你必须知道它的类型。

【讨论】:

  • “编译器怎么可能知道如何描述某事物,而它却一无所知?” - +1,但实际上,编译器确实知道一点。异常机制必须存储 some 类型信息,因为它必须将异常对象与 catch 子句进行匹配。但是标准没有定义这些信息或提供对它的访问,它是一个隐藏的实现细节。
  • 该类型信息远不足以执行此操作,并且没有任何实现可以改变它。
  • 听起来像一个挑战 ;-) 编译器扩展 __what() 返回一个字符串,其中包含当前异常的类型信息名称(易于实现),后跟更多描述其值的字符(实际上你可以很容易但相当乏味地涵盖了内置类型和大多数标准库,并且可能有一些用户定义类型的基本实现)。当然,这意味着编译器会为每种类型发出一些臃肿的代码来进行字符串转换,但是想想已经有多少operator&lt;&lt;。为所有事情都这样做,当然是不可能的。
【解决方案3】:

如果你知道你只抛出 std::exception 或子类,试试

catch(std::exception& e) {...e.what()... }

否则,正如 DeadMG 所写,由于您可以(几乎)扔掉所有东西,因此您无法假设您捕获的东西。

通常,catch(...) 仅应在使用编写不当或文档记录不佳的外部库时用作最后一道防线。所以你会使用层次结构

catch(my::specialException& e) {
      // I know what happened and can handle it
      ... handle special case
      }
catch(my::otherSpecialException& e) {
      // I know what happened and can handle it
      ... handle other special case
      }
catch(std::exception& e) {
      //I can at least do something with it
      logger.out(e.what());
      }
catch(...) {
     // something happened that should not have 
     logger.out("oops");
     }

【讨论】:

    【解决方案4】:

    从 C++11 开始,您可以使用指针捕获当前异常:

    std::exception_ptr p;     // default initialization is to nullptr
    
    try {
          throw 7;
    }
    catch(...)
    {
         p = std::current_exception();
    }
    

    这就像一个智能指针;只要至少有一个指针指向异常对象,它就不会被销毁。

    稍后(甚至可能在不同的函数中)您可以以与当前最佳答案类似的方式采取行动:

    try {
        if ( p )
            std::rethrow_exception(p);
    }
    catch(int x)
    {
    
    }
    catch(std::exception &y)
    {
    }
    

    【讨论】:

      【解决方案5】:

      我们实现异常的方式是,我们有自己的异常类,它们都派生自std::exception..

      我们的异常将包含异常消息、函数名、文件名和生成异常的行。这些都非常有用,不仅可以显示消息,还可以用于日志记录,这有助于很容易地诊断异常。因此,我们获得了有关生成的异常的全部信息。

      请记住,我们可以获取有关问题所在的信息。所以,在这方面,每一点信息都有帮助..

      【讨论】:

        【解决方案6】:

        引用bobah

        #include <iostream>
        
        #include <exception>
        #include <typeinfo>
        #include <stdexcept>
        
        int main()
        {
            try {
                throw ...; // throw something
            }
            catch(...)
            {
                std::exception_ptr p = std::current_exception();
                std::clog <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
            }
            return 1;
        }
        

        【讨论】:

        • 这不是标准的或可移植的。它依赖于编译器之间不同的特定于实现的细节。 std::exception_ptr 是一个指向 unspecified 类型的智能共享指针,因此不能保证 __cxa_exception_type() 存在
        猜你喜欢
        • 2012-06-04
        • 1970-01-01
        • 1970-01-01
        • 2016-06-26
        • 1970-01-01
        • 2015-06-26
        • 2011-01-11
        • 2013-06-22
        相关资源
        最近更新 更多