Cơ bản về ngoại lệ trong C++
Khái niệm cơ bản
- Exception (ngoại lệ) là cơ chế trong C++ dùng để xử lý lỗi phát sinh trong quá trình chương trình thực thi.
- Khi một lỗi xảy ra, chương trình có thể ném (throw) một ngoại lệ, sau đó tìm khối xử lý ngoại lệ (catch) phù hợp để xử lý lỗi đó.
- Cơ chế exception giúp tách biệt logic xử lý lỗi khỏi logic xử lý chính của chương trình.
Từ khóa chính
try: dùng để bao một đoạn code có thể phát sinh lỗi.throw: ném ra một ngoại lệ (thường là một giá trị hoặc đối tượng).catch: dùng để bắt và xử lý ngoại lệ được ném từ khốitry.
Cú pháp cơ bản
try {
// Mã có thể phát sinh lỗi
throw "Lỗi xảy ra!";
} catch (const char* msg) {
std::cerr << "Đã bắt ngoại lệ: " << msg << '\n';
}
- Nếu dòng
throwđược thực thi, chương trình sẽ thoát khỏitryvà chuyển đếncatchđầu tiên có kiểu tương ứng. - Nếu không có
catchphù hợp, chương trình sẽ kết thúc bằngstd::terminate.
Thứ tự hoạt động:
- Chạy mã trong
try. - Nếu
throwkhông xảy ra → bỏ quacatch. - Nếu
throwxảy ra → tìmcatchphù hợp theo thứ tự từ trên xuống. - Nếu tìm được → nhảy vào
catchtương ứng. - Nếu không tìm được → gọi
std::terminate()và kết thúc chương trình.
Ví dụ chi tiết
#include <iostream>
int chia(int a, int b) {
if (b == 0)
throw std::runtime_error("Chia cho 0");
return a / b;
}
int main() {
try {
std::cout << chia(10, 2) << '\n'; // In ra 5
std::cout << chia(5, 0) << '\n'; // Gây ngoại lệ
} catch (const std::runtime_error& e) {
std::cerr << "Lỗi: " << e.what() << '\n';
}
}
- Hàm
chianém ngoại lệstd::runtime_errornếu chia cho 0. - Khối
catchbắt được lỗi và in thông báo rõ ràng.
Các kiểu giá trị có thể throw
- Kiểu nguyên thủy:
throw 42; - Chuỗi ký tự:
throw "Lỗi"; - Đối tượng:
throw std::runtime_error("Lỗi nghiêm trọng"); - Bất kỳ kiểu nào, nhưng nên dùng đối tượng kế thừa từ
std::exceptionđể thuận tiện cho việc xử lý và gỡ lỗi.
Ghi chú quan trọng
- Không nên throw kiểu nguyên thủy (
int,const char*) trong dự án thực tế. Hãy luônthrowcác đối tượng cụ thể kế thừa từstd::exception. throwcó thể dùng trong hàm, constructor, hoặc bất kỳ đoạn code nào.- C++ không hỗ trợ
finallynhư Java, nhưng bạn có thể dùng RAII hoặcstd::unique_ptr,std::lock_guard,... để thay thếfinally.
Exception propagation (truyền ngoại lệ)
- Nếu
throwtrong một hàm không được bắt tại chỗ, ngoại lệ sẽ "lan truyền" lên caller (nơi gọi) cho đến khi gặptryphù hợp.
Ví dụ
void test() {
throw std::runtime_error("Lỗi test()");
}
int main() {
try {
test(); // Ngoại lệ từ test() được bắt ở đây
} catch (const std::exception& e) {
std::cerr << "Caught: " << e.what() << '\n';
}
}