Trong C++, có thể bắt tất cả các loại ngoại lệ bằng cú pháp catch(...) - gọi là catch-all handler.
Cú pháp
try {
// code có thể ném ngoại lệ
} catch (SpecificException& e) {
// Xử lý ngoại lệ cụ thể (ưu tiên cao hơn)
} catch (...) {
// Bắt TẤT CẢ ngoại lệ còn lại
}
Ví dụ
#include <iostream>
using namespace std;
void func(int a) {
try {
if (a == 0) throw 23.33; // ném double
if (a == 1) throw 's'; // ném char
if (a == 2) throw "error"; // ném const char*
if (a == 3) throw std::runtime_error("runtime");
} catch (...) {
cout << "Đã bắt ngoại lệ (bất kỳ loại nào)!\n";
}
}
int main() {
func(0); // double
func(1); // char
func(2); // const char*
func(3); // std::exception
func(4); // không ném
return 0;
}
Kết quả
Đã bắt ngoại lệ (bất kỳ loại nào)! Đã bắt ngoại lệ (bất kỳ loại nào)! Đã bắt ngoại lệ (bất kỳ loại nào)! Đã bắt ngoại lệ (bất kỳ loại nào)!
Lưu ý quan trọng
- Không thể truy cập đối tượng ngoại lệ trong
catch(...)- không biết kiểu, không lấy được thông tin - Nên đặt
catch(...)cuối cùng sau các catch cụ thể - Dùng cho: logging, cleanup, chuyển đổi ngoại lệ, tránh crash chương trình
- Trong destructor: luôn nên có catch-all để tránh ném ngoại lệ ra khỏi destructor
Ví dụ thực tế: Logging và re-throw
void criticalOperation() {
try {
// risky code
} catch (const std::exception& e) {
logError(e.what());
throw; // re-throw nguyên vẹn
} catch (...) {
logError("Unknown exception");
throw; // re-throw
}
}
C++11: std::current_exception
Có thể lấy đối tượng ngoại lệ trong catch-all:
catch (...) {
std::exception_ptr eptr = std::current_exception();
// lưu, chuyển thread, hoặc re-throw sau
std::rethrow_exception(eptr);
}