2012-02-27 60 views
25

Điều này có thể là một câu hỏi ngớ ngẩn, nhưng trong C++, khi tôi muốn ném một ngoại lệ .. tôi phải làm gì?Điều gì sẽ xảy ra khi ném ngoại lệ C++?

Tôi có phải ném tiêu chuẩn :: ngoại lệ hoặc được đặt trước bởi thư viện chuẩn không? Hoặc tôi nên ném một chuỗi hoặc int? Hay tôi chỉ cần ném bất cứ điều gì tôi cảm thấy là thích hợp?

+3

Không ném chuỗi hoặc int! Nếu bạn luôn ném các lớp con của 'std :: exception', bạn có thể đặt một mệnh đề catch-all trong' main' xử lý tất cả các ngoại lệ không được xử lý ở nơi khác và in 'what()' của ngoại lệ. –

Trả lời

31

Ném lớp học có nguồn gốc từ std::exception; nếu bạn #include <stdexcept>, bạn có thể chọn từ một số lớp học có nguồn gốc từ ready-made, useful.

Bắt nguồn từ std::exception cho phép trình xử lý của bạn theo một phong cách dễ nhận biết, vì bạn luôn có thể sử dụng .what() để nhận tin nhắn văn bản. Đừng ném các kiểu nguyên thủy, vì chúng không mang thông tin ngữ nghĩa.

+10

Tôi sẽ truy cập (mặc dù thực tế giống nhau) mà trong hầu hết trường hợp mọi người nên lấy được ngoại lệ của họ từ std :: runtime_error (mà chính nó xảy ra được bắt nguồn từ std :: exception) –

8

Nói chung mọi người không ném std :: ngoại lệ trực tiếp vì lý do đơn giản là nó không lưu trữ bất kỳ thông báo lỗi nào. Sẽ không có bất cứ điều gì cho phương pháp quay trở lại. Đôi khi tôi bị nhầm lẫn về điều này bởi vì MSVC cung cấp một phần mở rộng không chuẩn cho một hàm tạo tham số trong std :: exception chấp nhận một chuỗi.

Bạn có thể chọn trong số các lớp ngoại lệ hiện có như std :: runtime_exception hoặc xác định của riêng bạn. Điều này hơi chủ quan nhưng tôi khuyên bạn nên giữ số lượng các lớp ngoại lệ ở mức tối thiểu vì RAII có thể loại bỏ rất nhiều nhu cầu có nhiều nhánh mã và bắt các khối ngoại lệ khác nhau. Thông thường, thông điệp kết hợp với mã RAII phù hợp là đủ để phục hồi một cách duyên dáng từ bất kỳ ngoại lệ nào.

Và cuối cùng, tôi khuyên tất cả các trường hợp ngoại lệ bạn ném kế thừa từ std :: exception vì các lý do tương tự. Bạn không muốn phải xả rác mã của bạn với nhiều khối catch khác nhau cho các loại ngoại lệ khác nhau nếu bạn có thể tránh được nó. Giải quyết vấn đề thường xuyên nhất có thể.

+1

Bạn không có nghĩa là 'std :: runtime_error'? –

1

Không giống như java, bạn có thể ném bất kỳ thứ gì (int, string, MyClass, ...) mà bạn muốn. Nhưng hãy nghe Kerrek. :)

0

Thông thường, bạn sẽ muốn ném một trong các trường hợp ngoại lệ bắt nguồn từ std::exception như những người khác đã nói.

Thỉnh thoảng tôi đã ném các loại khác, nhưng chỉ khi nó bị bắt trong cùng một khối và giá trị là một cái gì đó hữu ích trong ngữ cảnh đó.

+0

Nếu bạn đang bắt "trong cùng một khối", có thể bạn không nên ném ngoại lệ ngay từ đầu. Trường hợp ngoại lệ dành cho các điều kiện đặc biệt, nhưng nếu bạn có thể xử lý tình trạng ngay tại đó, thì có vẻ như nó chỉ là một phần của luồng chương trình thông thường. (Và đừng quên rằng * ném * một ngoại lệ có thể đắt hơn rất nhiều so với việc chỉ kiểm tra một số địa phương.) –

+0

@KerrekSB, tôi không thể nhớ chính xác hoàn cảnh mà tôi đã làm điều này, nhưng tôi chắc chắn rằng nó là một điều kiện đặc biệt không phải là một phần của dòng * bình thường *. Có lẽ cũng lồng nhau sâu sắc nơi các phương pháp thay thế sẽ trở nên xấu hơn. –

+2

Đủ công bằng. Có * là * tình huống mà một ngoại lệ có thể làm cho một thuật toán phức tạp rõ ràng hơn và dễ hiểu hơn ... –

2

Ngoại lệ chính để ném nội dung bắt nguồn từ std::exception sẽ là nếu bạn đang sử dụng một số khung (ví dụ: MFC) với phân cấp ngoại lệ của riêng nó. Trong trường hợp đó, bạn thường muốn lấy được từ một vị trí thích hợp trong hệ thống phân cấp của họ thay thế. Lưu ý rằng tôi không đặc biệt cố gắng giữ MFC như là một ví dụ về xử lý ngoại lệ sạch (hoặc thiết kế sạch nói chung), chỉ là một ví dụ về một khuôn khổ bao gồm một hệ thống phân cấp ngoại lệ. Khi bạn đang sử dụng một khung công tác đã định nghĩa một hệ thống phân cấp ngoại lệ, bạn thường sử dụng nó tốt hơn.

Nói cách khác, không giống như tùy chọn trong C++ nếu không, thường được chấp nhận rằng ngoại lệ phải là một phân cấp đơn nguyên, nguyên khối với một gốc đơn. Đối với thư viện chuẩn, gốc đơn đó là std::exception, nhưng các khung công tác khác có các lựa chọn thay thế và nếu chúng cung cấp một phương pháp bạn thường muốn phù hợp với bạn.

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