如何自定义未捕获的异常终止行为?

时间:2013-06-23 07:55:55

标签: c++ exception-handling terminate

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&,则默认值与典型值相同。

Note2 :根据目前为止的两条建议,“通过捕获异常来定制未捕获的异常”。看起来像代码中的内容。我想知道是否有办法做同样的事情而不向我写的所有 try-catch代码添加main()块。

#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';
}

3 个答案:

答案 0 :(得分:3)

用于自定义未捕获异常处理的钩子正在捕获异常。

答案 1 :(得分:3)

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

#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中并在my_improve_terminate()之前调用main,因此当包含某个文件时,它将成为新的默认值。

答案 2 :(得分:2)

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