2010-09-04 19 views
21

Tôi có thể lấy mô tả về một ngoại lệ bị bắt bởiC++ được mô tả về một ngoại lệ bị bắt trong catch (...) chặn

catch(...) 

khối? một cái gì đó như .what() của std :: exception.

+1

Trong C++ 11 rethrowing của ' std :: current_exception' có thể được sử dụng để nhận thông điệp 'what' ngoại lệ trong khối catch-all: http://stackoverflow.com/a/37222762/5447906 –

Trả lời

38

Có một thủ thuật bạn có thể sử dụng:

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"; 
    } 

và như vậy, càng nhiều loại khác nhau như bạn nghĩ có thể được ném ra. Nếu bạn thực sự không biết gì về những gì có thể được ném sau đó ngay cả thứ hai đến cuối cùng là sai, bởi vì ai đó có thể ném một char* mà không trỏ đến một chuỗi nul chấm dứt.

Nói chung, một ý tưởng không tốt khi ném bất kỳ thứ gì không phải là lớp học std::exception hoặc có nguồn gốc. Lý do std::exception tồn tại là cho phép mọi người ném và bắt các đối tượng mà họ có thể làm điều gì đó hữu ích. Trong một chương trình đồ chơi mà bạn chỉ muốn ra khỏi đó và thậm chí không thể bị làm phiền để bao gồm một tiêu đề tiêu chuẩn, OK, có thể ném một int hoặc một chuỗi chữ. Tôi không nghĩ rằng tôi sẽ làm cho một phần của một giao diện chính thức. Bất kỳ trường hợp ngoại lệ bạn ném là một phần của giao diện chính thức của bạn, ngay cả khi bạn bằng cách nào đó quên tài liệu cho họ.

+2

Xin chào; đây là một câu trả lời tuyệt vời. Tôi đã tìm kiếm một thời gian để tìm bằng chứng trong các tài liệu tiêu chuẩn rằng đây là hành vi tiêu chuẩn, nhưng không thể tìm thấy bất kỳ hành vi nào. Bạn có biết chắc chắn rằng đây là hành vi tiêu chuẩn không? (Có nghĩa là, nhập một 'try'-block mới bên trong một' catch (...) {} 'và rethrowing một ngoại lệ để xác định loại của nó.) – NHDaly

+1

Làm việc từ bộ nhớ: tìm kiếm văn bản về tuổi thọ của ngoại lệ hiện tại (cho đến khi bạn thoát khỏi mệnh đề catch), và hiệu ứng của một 'throw' không có toán hạng (trả về ngoại lệ hiện tại). –

5

Khối đó có thể bắt int, hoặc const char * hoặc bất kỳ thứ gì. Làm thế nào để trình biên dịch có thể biết cách mô tả một cái gì đó khi nó không biết gì về nó? Nếu bạn muốn nhận được thông tin ngoại lệ, bạn phải biết loại.

+5

" Làm thế nào để trình biên dịch có thể biết cách mô tả điều gì đó khi nó biết không có gì về nó? " - 1, nhưng thực ra, trình biên dịch không biết một chút về nó. Cơ chế ngoại lệ phải lưu trữ thông tin loại * một số *, vì nó phải khớp với đối tượng ngoại lệ đối với các mệnh đề bắt. Nhưng tiêu chuẩn không xác định thông tin này hoặc cung cấp quyền truy cập vào nó, nó là một chi tiết triển khai ẩn. –

+0

Thông tin loại đó không có ở đâu đủ để thực hiện thao tác này và không có triển khai nào có thể thay đổi điều đó. – Puppy

+1

âm thanh như một thách thức ;-) Một phần mở rộng trình biên dịch '__what()' trả về một chuỗi chứa tên typeinfo của ngoại lệ hiện tại (dễ thực hiện), tiếp theo là nhiều ký tự mô tả giá trị của nó (trong thực tế bạn có thể dễ dàng các loại nội trang dựng sẵn và hầu hết thư viện chuẩn và có thể có một số triển khai cơ bản cho các loại do người dùng xác định). Tất nhiên nó sẽ có nghĩa là trình biên dịch phát ra một số mã bloaty cho mọi loại để thực hiện chuyển đổi chuỗi của nó, nhưng sau đó nghĩ có bao nhiêu toán tử << 'đã xuất hiện ở đó rồi. Làm điều đó cho tất cả mọi thứ, tất nhiên là không thể. –

4

Nếu bạn biết bạn chỉ ném std :: ngoại lệ hoặc lớp con, hãy thử

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

Nếu không, như DeadMG viết, vì bạn có thể ném (gần như) tất cả mọi thứ, bạn không thể giả định bất cứ điều gì về những gì bạn bắt gặp.

Thường bắt (...) chỉ nên được sử dụng làm biện pháp phòng thủ cuối cùng khi sử dụng thư viện bên ngoài được viết sai hoặc được ghi tài liệu. Vì vậy, bạn sẽ sử dụng một hệ thống phân cấp

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"); 
    } 
2

Làm sao chúng ta có trường hợp ngoại lệ của chúng tôi thực hiện là, chúng tôi có các lớp học của chúng tôi riêng ngoại lệ, mà tất cả đều có nguồn gốc từ std::exception ..

trường hợp ngoại lệ của chúng tôi sẽ chứa nhắn ngoại lệ, Chức năng tên, Tên tệp và dòng nơi ngoại lệ được tạo. Đây là tất cả hữu ích không chỉ để hiển thị các tin nhắn mà còn có thể được sử dụng cho đăng nhập giúp chẩn đoán ngoại lệ khá dễ dàng. Vì vậy, chúng tôi có được toàn bộ thông tin về các ngoại lệ được tạo ra.

Hãy nhớ ngoại lệ là dành cho chúng tôi để nhận thông tin về những gì đã xảy ra. Vì vậy, mỗi bit thông tin giúp trong vấn đề này ..

3

Kể từ C++ 11 bạn có thể nắm bắt được ngoại lệ hiện tại với một con trỏ:

std::exception_ptr p;  // default initialization is to nullptr 

try { 
     throw 7; 
} 
catch(...) 
{ 
    p = std::current_exception(); 
} 

này hoạt động như một con trỏ thông minh; miễn là có ít nhất một con trỏ trỏ tới đối tượng ngoại lệ, nó không bị phá hủy.

Sau đó (thậm chí trong một chức năng khác nhau), bạn có thể hành động theo một cách tương tự như câu trả lời đầu hiện nay:

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

} 
catch(std::exception &y) 
{ 
} 
2

Trích dẫn 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; 
} 
+1

Đây không phải là tiêu chuẩn hoặc di động. Nó dựa vào * chi tiết cụ thể triển khai * khác nhau giữa các trình biên dịch. 'std :: exception_ptr' là một con trỏ chia sẻ thông minh với kiểu * không xác định *, vì vậy không có gì đảm bảo rằng' __cxa_exception_type() 'tồn tại –

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