2011-02-03 81 views
10

的类型,说我有:C++ - 寻找陷入默认异常

try 
{ 
externalLibrary::doSomething(); 
} 
catch (std::exception &e) 
{ 
//yay I know what to do 
} 
catch (...) 
{ 
//darn, I've no idea what happened! 
} 

有可能是你会得到一个异常的情况下,你不知道它的来自或为什么 - 在一些外部库没有调试信息。有没有办法找到抛出的东西或以其他方式获取与其相关的数据?他们可能做:

throw myStupidCustomString("here is some really useful information"); 

但我永远不会知道,如果我赶上...

在MSVC++ 2008,如果它很重要的工作。

回答

6

因为C++是静态类型的,所以你必须捕获一个已知类型。但是,您可以调用一个外部函数(或一组函数)来处理在您调用它们时未知的异常类型。如果这些处理程序都具有已知类型,则可以注册它们以进行动态尝试。

struct myStupidCustomString { 
    myStupidCustomString(char const *what) : what (what) {} 
    char const *what; 
}; 

void throws() { 
    throw myStupidCustomString("here is some really useful information"); 
} 

// The external library can provide a function, or you can provide a wrapper, which 
// extracts information from "unknown" exception types. 
std::string extract_from_unknown_external_exception() { 
    try { throw; } 
    catch (myStupidCustomString &e) { 
    return e.what; 
    } 
    catch (...) { 
    throw; // Rethrow original exception. 
    } 
} 

Use

void example() { 
    try { throws(); } 
    catch (...) { 
    try { 
     std::string extracted = extract_from_unknown_external_exception(); 
     std::cout << "extracted: " << extracted << '\n'; 
    } 
    catch (...) { 
     // Chain handlers for other types; e.g. exception types from other libraries. 
     // Or do something generic for the unknown exception. 

     // Or rethrow the original unknown exception: 
     throw; 
    } 
    } 
} 

Handler chain

typedef std::string Extract(); 
std::vector<Extract*> chain (1, &extract_from_unknown_external_exception); 
// Chain would normally be initialized using whatever scheme you prefer for 
// initializing global objects. 
// A list or other container (including a manual linked list that doesn't 
// require dynamic allocation) may be more appropriate, depending on how you 
// want to register and unregister handlers. 
std::string process_chain() { 
    for (std::vector<Extract*>::iterator x = chain.begin(); x != chain.end(); ++x) { 
    try { 
     return (*x)(); 
    } 
    catch (...) {} // That handler couldn't handle it. Proceed to next. 
    } 
    throw; // None could handle it, rethrow original exception. 
} 

void example() { 
    try { throws(); } 
    catch (...) { 
    try { 
     std::string extracted = process_chain(); 
     std::cout << "extracted: " << extracted << '\n'; 
    } 
    catch (...) { 
     throw; // Rethrow unknown exception, or otherwise handle it. 
    } 
    } 
} 

最后,如果你知道实现细节,你可以使用这些提取任何额外的信息,请执行会公开。 C++ 0x也以便携的方式公开了一些细节;看看std :: exception_ptr。

1

你不能在标准的C++。我认为这样的例外是非常特殊的,并且通过尝试记录你有一个不好的例外的事实来处理它们,然后尝试退出程序,而你仍然可以。

如果幸运的话,您可以保存任何数据。

2

有没有办法知道在C异常的类型++(在catch(...)块,我的意思是,五言的)

你可能只是希望你知道究竟externalLibrary::doSomething();呢,如果你写它,或,就像你的情况一样,你可能只是希望,如果有这样的话,那么externalLibrary::doSomething();就有非常好的文档并阅读它。所有好的库都有详细的文档。

+0

根据我的经验,异常的详细文档并不像体面的params文档那样普遍。但是,如果是这样,我只需要测试标准的可能性......系统异常呢? – 2011-02-03 11:35:25

+0

你是什么意思“系统异常呢?”我不知道他们是否可以在C++程序中被捕获:?此外,我使用的大多数库都有自己的异常层次结构,并且有很好的文档记录。但是,当然,这并不意味着所有图书馆都有这样的事情。另外,如果它是C库,你知道,没有例外抛出。 – 2011-02-03 11:40:11

+0

我的意思是,没有特殊的方法来捕捉像null-ptr访问,div/0之类的东西吗?我认为有方法可以在第三方库存在bug的情况下捕获这些问题? – 2011-02-03 14:36:43

15

如果您使用gcc或CLANG,则可以使用技巧来了解“未知”异常类型。请记住,这是非标准的!

#include <cstdlib> 
#include <iostream> 
#include <cxxabi.h> 


using namespace __cxxabiv1; 

std::string util_demangle(std::string to_demangle) 
{ 
    int status = 0; 
    char * buff = __cxxabiv1::__cxa_demangle(to_demangle.c_str(), NULL, NULL, &status); 
    std::string demangled = buff; 
    std::free(buff); 
    return demangled; 
} 

struct MyCustomClass 
{}; 

int main(int argc, char * argv[]) 
{ 
    try 
    { 
     throw MyCustomClass(); 
    } 
    catch(...) 
    { 
     std::cout << "\nUnknown exception type: '" << util_demangle(__cxa_current_exception_type()->name()) << "'" << std::endl; 
    } 
    return(0); 
}