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ỏitry
và chuyển đếncatch
đầu tiên có kiểu tương ứng. - Nếu không có
catch
phù 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
throw
không xảy ra → bỏ quacatch
. - Nếu
throw
xảy ra → tìmcatch
phù hợp theo thứ tự từ trên xuống. - Nếu tìm được → nhảy vào
catch
tươ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
chia
ném ngoại lệstd::runtime_error
nếu chia cho 0. - Khối
catch
bắ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ônthrow
các đối tượng cụ thể kế thừa từstd::exception
. throw
có thể dùng trong hàm, constructor, hoặc bất kỳ đoạn code nào.- C++ không hỗ trợ
finally
như 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
throw
trong 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ặptry
phù 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';
}
}