2011-02-03 34 views
10

Nói rằng tôi có:C++ - tìm loại một ngoại lệ mặc định bắt

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

Có thể có trường hợp, bạn có được một ngoại lệ và bạn không biết nó ở đâu đến từ hoặc lý do tại sao - trong một số thư viện bên ngoài với không có thông tin gỡ lỗi. Có cách nào để tìm thấy những gì đã được ném, hoặc nếu không có được bất kỳ dữ liệu nào liên kết với nó? Họ thể được thực hiện:

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

Nhưng tôi chưa bao giờ biết nếu tôi bắt ...

Làm việc trong MSVC++ 2008 nếu vấn đề.

Trả lời

6

Vì C++ được nhập tĩnh, bạn phải bắt được một loại đã biết. Tuy nhiên, bạn có thể gọi một hàm bên ngoài (hoặc tập hợp các hàm) xử lý các loại ngoại lệ không xác định tại thời điểm bạn gọi chúng. Nếu tất cả các trình xử lý này có các loại đã biết, bạn có thể đăng ký chúng để được thử động.

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. 
    } 
    } 
} 

Cuối cùng, nếu bạn biết chi tiết cụ thể thực hiện, bạn có thể sử dụng những trích xuất bất kỳ thông tin bổ sung thực hiện của bạn cho thấy. C++ 0x cho thấy một số chi tiết cụ thể theo cách di động; nhìn vào std :: exception_ptr.

+0

Xin chào, tôi nghĩ rằng đây là một câu trả lời tuyệt vời.Tuy nhiên, tôi không thể tìm thấy bất kỳ thông tin nào trong tiêu chuẩn về việc đây có phải là hành vi tiêu chuẩn hay không. Tôi đã thử nghiệm nó, và nó hoạt động cả trong VisualStudio, GCC, và LLVM, nhưng tôi không hoàn toàn chắc chắn lý do tại sao. Vì vậy, việc nhập một khối 'try {} catch() {}' mới không ảnh hưởng đến ngoại lệ hiện tại theo bất kỳ cách nào? Cảm ơn! – NHDaly

+0

Tôi cho rằng tôi cũng không chắc tại sao nó không hoạt động .. Có vẻ hợp lý với tôi rằng việc tham gia vào khối thử sẽ không ảnh hưởng đến bất kỳ ngoại lệ nào, nhưng tôi đoán tôi chỉ muốn kiểm tra lại. – NHDaly

1

Bạn không thể ở chuẩn C++. Tôi sẽ xem xét ngoại lệ như vậy là rất đặc biệt, và xử lý chúng bằng cách cố gắng để đăng nhập một thực tế rằng bạn đã có một ngoại lệ xấu, và sau đó cố gắng để bỏ chương trình, trong khi bạn vẫn có thể.

Nếu bạn may mắn, bạn có thể lưu bất kỳ dữ liệu nào.

2

Không có cách nào để biết loại trừ trong C++ (trong catch(...) khối, ý tôi là, của cource)

Bạn chỉ có thể hy vọng rằng bạn biết chính xác những gì externalLibrary::doSomething(); không, nếu bạn đã viết nó, hoặc , như trong trường hợp của bạn, bạn chỉ có thể hy vọng, rằng có tài liệu thực sự tốt đẹp cho externalLibrary::doSomething(); và đọc nó, nếu có. Tất cả các thư viện tốt đều có tài liệu chi tiết.

+0

Tài liệu chi tiết về ngoại lệ không phổ biến như tài liệu phong nha về thông số, theo kinh nghiệm của tôi. Nhưng nếu đó là nó như thế nào, tôi sẽ chỉ phải kiểm tra khả năng tiêu chuẩn ... những gì về ngoại lệ hệ thống? –

+0

Ý của bạn là gì về "ngoại lệ hệ thống?" Tôi không biết nếu họ có thể bị bắt trong một chương trình C++:? Ngoài ra, hầu hết các thư viện, tôi đã sử dụng, đều có hệ thống phân cấp ngoại lệ của riêng chúng. Nhưng, tất nhiên, điều này không có nghĩa là tất cả các thư viện đều có những thứ như vậy. Ngoài ra, nếu đó là C lib, bạn biết đấy, không có ngoại lệ nào được ném ra. –

+0

Ý tôi là, không có cách nào đặc biệt để nắm bắt những thứ như truy cập null-ptr, div/0 và cứ tiếp tục như vậy? Tôi nghĩ rằng có nhiều cách để bắt các vấn đề như vậy mà lib của bên thứ 3 bị lỗi? –

15

Nếu bạn sử dụng gcc hoặc CLANG, bạn có thể sử dụng mẹo để biết loại ngoại lệ 'không xác định'. Hãy nhớ rằng đây không phải là tiêu chuẩn!

#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); 
} 
+0

Omg. Tôi có thể hôn bạn ngay bây giờ. Cảm ơn bạn <3 –

Các vấn đề liên quan