2012-07-02 29 views

Trả lời

13

Trang web đó ngu ngốc và dạy thiết kế kém.

Nếu bạn ném int hoặc char*, thì bạn sẽ chỉ phải bắt nó bằng cách sử dụng int hoặc char*. Bạn có thể đủ điều kiện với const.

Nếu bạn ném std::runtime_error, thì bạn có thể bắt bằng cách sử dụng std::runtime_error const & hoặc lớp cơ sở std::exception const &.

Vì vậy, điều gì tốt về nó?

Các tốt về nó là nếu bạn ném một ngoại lệ sử dụng một lớp học mà cuối cùng có nguồn gốc từ std::exception, sau đó bạn có thể viết chỉ ONE catch khối mà chấp nhận ngoại lệ như std::exception const&, không phân biệt which derived class được sử dụng để ném ngoại lệ.

Dưới đây là một ví dụ:

void f(A & a) 
{ 
    if (!check_arg(a)) 
    { 
      throw std::invalid_argument("invalid argument"); 
    } 
    else if (!check_size(a)) 
    { 
      throw std::length_error("invalid length");    
    } 

    //code 
    if(someCondition) 
    { 
      //assume your_own_defined_exception's ultimate base is std::exception 
      throw your_own_defined_exception("condition unsatisfied");       
    } 
    //... 

} 

Bây giờ là phần thú vị:

try 
{ 
     f(a); //it can throw exception of at least 3 types! 
} 
catch(std::exception const &e) //all types can be caught by just one catch! 
{ 
    //handle this case 
} 

Các tốt là bạn không cần viết bacatch khối chỉ vì f() có thể ném ba các loại ngoại lệ khác nhau. Bạn có thể viết nhiều hơn một catch để xử lý chúng khác nhau nếu điều đó có lợi cho bạn theo một cách nào đó. Nhưng điểm cần lưu ý ở đây là: đó là không phải một yêu cầu!

Tóm lại, bạn có thể tận dụng lợi thế của phân cấp lớp.

+0

Vì vậy, về cơ bản nó tự nhiên cho phép thừa kế để đơn giản hóa thiết kế xử lý lỗi. Khá thanh lịch. Nếu tôi định nghĩa lớp ngoại lệ của riêng mình và làm theo cách đó, tôi có thể tạo ra kết quả tương tự, đúng không? –

+3

@StevenLu Nếu bạn lấy được lớp ngoại lệ của riêng bạn, thì bạn phát minh lại bánh xe và có khả năng phá vỡ mã phụ thuộc vào việc bắt std :: exception. Trong khi điều này có thể tốt cho các dự án cá nhân của bạn, nó làm cho mã của bạn khó phân phối cho người khác. Cách tiếp cận tiêu chuẩn là có một hệ thống phân cấp ngoại lệ dành riêng cho ứng dụng phân lớp 'std :: exception'. Ví dụ, có tất cả các ngoại lệ của bạn là các lớp con của 'StevenLuException', là một lớp con của' std :: exception'. – sfstewman

+0

@StevenLu: Nếu lớp ngoại lệ của bạn xuất phát từ 'std :: exception', thì có đó là thiết kế thanh lịch. Xem ngoại lệ * thứ ba * được gọi là 'your_own_defined_exception' trong mã ví dụ của tôi. Tôi nói nó đã được bắt nguồn từ 'std :: exception' cuối cùng. – Nawaz

1

Chủ yếu là vì khi bạn làm việc với những người khác, bạn phải đồng ý về những gì cần nắm bắt. Nếu tôi cố bắt một số const std::exception& và bạn ném const char*, thì tôi sẽ không bắt được nội dung của bạn và những điều xấu có thể xảy ra.

Nó không thực sự quan trọng loại được ném và bị bắt, miễn là tất cả mọi người dính vào nó. Tôi đoán std::exception được chọn trên const char* vì nó cho phép bạn đặt nhiều hơn chỉ một chuỗi vào đối tượng ngoại lệ. Nó chỉ linh hoạt hơn.

2

Nếu bạn làm cho nó một quy tắc trong mã của bạn để ném ngoại lệ chỉ bắt nguồn từ std :: exception sau đó bắt chúng dễ dàng hơn. Nói cách khác, bạn chỉ có thể có một điều khoản bắt trên std :: exception:

catch (std::exception& e) 
{ 
    log_message(e); 
    throw; 
} 

Nhưng nếu bạn không tuân theo quy tắc này thì bạn phải viết mệnh đề bắt khi không cần.

+0

có rất ít lợi ích khi bắt và thử lại ở mọi lớp, chỉ sử dụng mệnh đề 'catch' nếu bạn thực sự có điều gì đó cần làm (và trong C++, với RAII, điều này đủ hiếm) hoặc" nuốt "nó. –

+0

Tôi thấy hữu ích khi tạo theo dõi ngăn xếp cho các ngoại lệ không được mong đợi. Nó giúp chẩn đoán một lỗi và theo dõi nơi ngoại lệ orginated từ. – sashang

+0

Tôi đồng ý rằng ngăn xếp là hữu ích, tuy nhiên có hai nhược điểm đối với cách tiếp cận của bạn. Đầu tiên nó cắt mã, nó không còn rõ ràng khi một hành động * cụ thể * được thực hiện trong trường hợp ngoại lệ. Thứ hai, nó là một con heo hiệu suất, bởi vì việc thực hiện ngoại lệ Zero Cost được sử dụng bởi các trình biên dịch phổ biến như gcc hoặc Clang đặt một hình phạt khắc nghiệt trên ném. Có khác, và tôi tìm thấy tốt hơn, lựa chọn thay thế. Nền tảng mã cụ thể để nắm bắt các ngăn xếp tại các điểm ném là một; khác là sử dụng RAII để đăng nhập "ghi chú" được thêm vào ngoại lệ trong khi thư giãn. –

1

Một điểm bổ sung từ anh câu trả lời khác là thế này -

Nếu bạn ném một int hoặc một chuỗi và bạn muốn bắt một lỗi cụ thể mà bạn không thể. Bạn phải nắm bắt tất cả các ngoại lệ "int" và sau đó so sánh các trường hợp bạn muốn nắm bắt, sau đó so sánh lại bất kỳ trường hợp nào bạn chưa sẵn sàng giải quyết. Nếu bạn kế thừa từ ngoại lệ, bạn có thể bắt ngoại lệ cụ thể mà bạn muốn xử lý và vẫn có lợi thế là bạn có thể bắt std :: exception nếu bạn muốn xử lý tất cả.

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