【问题标题】:How to customize uncaught exception termination behavior?如何自定义未捕获的异常终止行为?
【发布时间】:2013-06-19 23:19:06
【问题描述】:

g++clang++(至少在Linux 中)中,在抛出异常但未捕获(未捕获的异常)后会显示以下典型消息:

terminate called after throwing an instance of 'std::runtime_error'
  what():  Bye

例如在:

#include<stdexcept>
int main(){
  throw std::runtime_error("Bye");
}

如何在仍然可以完全访问抛出的异常的同时自定义错误消息?

文档(http://www.cplusplus.com/reference/exception/set_unexpected/)提到了set_unexpected(和set_terminate),但我不知道unexpected_handle如何实际访问抛出的异常,例如调用e.what()或其他东西.

注意:这背后的原因是我想定制一个更复杂的异常类层次结构的消息,它比简单的what()有更多的信息,如果这种类型我想显示它抛出异常(但如果抛出简单的std::exception&amp;,则默认与典型相同。

注2:根据目前的两条建议,“通过捕获异常来自定义未捕获的异常”。看起来像代码中的内容。我想知道是否有一种方法可以在不向我编写的 all main() 代码中添加 try-catch 块的情况下做同样的事情。

#include<stdexcept>
int main() try{
   ....
}catch(std::exception& e){
  std::clog << "terminate called after throwing an instance of '" << typeid(e) << "'\n"
            << "  what(): " << e.what() << '\n'
            << "otherinfo, like current time\n";
}catch(alternative_exception& e){
  std::clog << "terminate called after throwing an instance of '" << typeid(e) << "'\n"
            << "  what(): " << e.what() << '\n'
            << "  where(): " << e.where() << '\n'
            << "  how(): " << e.how() << '\n'
            << "othermember(): " << e.othermember() << '\n';
}

【问题讨论】:

标签: c++ exception-handling terminate


【解决方案1】:

自定义处理未捕获异常的钩子是捕获异常。

【讨论】:

  • 但是在某些情况下您不能这样做。例如,静态对象构造函数。
  • @Pete,是否也意味着在所有 main() 程序周围放置一个 try-catch?除了这很烦人之外,celtschk 是不是一个不起作用的反例? (请参阅我的编辑)。
  • @celtschk - 函数尝试块处理构造函数抛出的异常。
  • @PeteBecker:只有当你是类的作者,因此才能编写构造函数。
  • @celtschk - 或者如果您编写一个派生类,该类转发到基类型的构造函数并捕获抛出的异常。
【解决方案2】:

除了实际捕获您关心的异常之外,std::set_terminate()std::current_exception() (C++11) 应该足以做一些有趣的事情。

【讨论】:

  • 谢谢,我根据这些提示添加了答案。看来我不需要使用std::current_exception
【解决方案3】:

根据@JonPurdy(已接受)的回答,我尝试了这段似乎可以工作的代码,至少在 Linux 中使用 gcc 4.7.2 和 clang 3.2。我不知道它有多健壮或可移植(欢迎 cmets),我尽量不对默认终止处理程序做出假设:

#include<stdexcept>
#include<iostream>
#include<typeinfo> // for typeid

// a special exception, can be an abstract class, here it is concrete class to make the example shorter.
struct debug_exception : std::runtime_error{
    std::string where_;
    debug_exception(std::string what, std::string where) : std::runtime_error(what), where_(where){}
    virtual const char* where() const{return where_.c_str();}
};

std::terminate_handler my_default_terminate;

void my_verbose_terminate_handler(){
    try{
        throw;
    }catch(debug_exception& e){
        std::cerr << "my_verbose_terminate_handler called after throwing an instance of " 
                  << typeid(e).name() << std::endl; // or demangled
        std::cerr << "  what(): "  << e.what()  << std::endl;
        std::cerr << "  where(): " << e.where() << std::endl;
    }catch(...){
        my_default_terminate(); // probably __gnu_cxx::__verbose_terminate_handler();
    }
}
std::terminate_handler my_improve_terminate(){
    my_default_terminate = std::set_terminate(my_verbose_terminate_handler);
    return my_default_terminate;
}

int main(){
    my_improve_terminate();
//  throw 2; // says the default "terminate called after throwing an instance of 'int'"
//  throw std::runtime_error("bye"); // says the default "terminate called ... what(): bye"
    throw debug_exception("Bye", __PRETTY_FUNCTION__); // says my_verbose_terminate_handler called ... what(): Bye, where(): int main()"
}

现在我正在尝试将所有代码包装在 class 中,并在 main 之前调用 my_improve_terminate(),因此当包含某个文件时,它将成为新的默认值。

【讨论】:

  • 注意 typeid(e).name() 并不总是特别清晰。
  • @aschepler,是的,我应该像 __gnu_cxx::__verbose_terminate_handler 那样解散它;我不想让这个例子太长。已添加注释。
  • 顺便说一句,我找不到 __gnu_cxx::__verbose_terminate_handler 的实现,这是 gnu 标准中的默认终止处理程序。我在哪里可以找到它?它是一个可以查找的真正功能吗?
猜你喜欢
  • 2017-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-05
  • 2016-03-25
  • 1970-01-01
相关资源
最近更新 更多