C++ Xử lý ngoại lệ: Ví dụ thử, bắt, ném
Xử lý ngoại lệ trong C++?
Xử lý ngoại lệ trong C++ cung cấp cho bạn cách xử lý các trường hợp không mong muốn như lỗi thời gian chạy. Vì vậy, bất cứ khi nào một tình huống bất ngờ xảy ra, việc điều khiển chương trình sẽ được chuyển sang các chức năng đặc biệt được gọi là bộ xử lý.
Để nắm bắt các ngoại lệ, bạn đặt một số phần mã dưới sự kiểm tra ngoại lệ. Phần mã được đặt trong khối try-catch.
Nếu một tình huống đặc biệt xảy ra trong phần mã đó, một ngoại lệ sẽ được đưa ra. Tiếp theo, trình xử lý ngoại lệ sẽ nắm quyền kiểm soát chương trình.
Trong trường hợp không có trường hợp đặc biệt nào xảy ra, mã sẽ thực thi bình thường. Các trình xử lý sẽ bị bỏ qua.
Với C++ hướng dẫn, bạn sẽ học:
Tại sao phải xử lý ngoại lệ?
Đây là lý do sử dụng Xử lý ngoại lệ trong C++:
- Bạn sẽ tách mã xử lý lỗi khỏi mã thông thường. Mã sẽ dễ đọc hơn và dễ bảo trì hơn.
- Các hàm có thể xử lý các ngoại lệ mà chúng chọn. Ngay cả khi một hàm đưa ra nhiều ngoại lệ, nó sẽ chỉ xử lý một số ngoại lệ. Người gọi sẽ xử lý các ngoại lệ chưa được phát hiện.
Từ khóa xử lý ngoại lệ
Xử lý ngoại lệ trong C++ xoay quanh ba từ khóa này:
- quăng– khi một chương trình gặp sự cố, nó sẽ đưa ra một ngoại lệ. Từ khóa ném giúp chương trình thực hiện cú ném.
- bắt– một chương trình sử dụng trình xử lý ngoại lệ để bắt ngoại lệ. Nó được thêm vào phần chương trình mà bạn cần xử lý vấn đề. Nó được thực hiện bằng cách sử dụng từ khóa Catch.
- thử– khối thử xác định khối mã mà một số ngoại lệ nhất định sẽ được kích hoạt. Theo sau nó là một/nhiều khối bắt.
Giả sử một khối mã sẽ đưa ra một ngoại lệ. Ngoại lệ sẽ bị bắt bằng một phương pháp sử dụng từ khóa thử và bắt. Khối thử/bắt phải bao quanh mã có thể đưa ra ngoại lệ. Mã như vậy được gọi là mã được bảo vệ.
cú pháp
Việc thử/bắt có cú pháp này:
try { // the protected code } catch( Exception_Name exception1 ) { // catch block } catch( Exception_Name exception2 ) { // catch block } catch( Exception_Name exceptionN ) { // catch block }
- Mặc dù chúng ta có một câu lệnh thử nhưng chúng ta có thể có nhiều câu lệnh bắt.
- ExceptionName là tên của ngoại lệ cần bắt.
- Ngoại lệ1, ngoại lệ2 và ngoại lệN là tên do bạn xác định để đề cập đến các ngoại lệ.
Ví dụ 1:
#include<iostream> #include<vector> using namespace std; int main() { vector<int> vec; vec.push_back(0); vec.push_back(1); // access the third element, which doesn't exist try { vec.at(2); } catch (exception& ex) { cout << "Exception occurred!" << endl; } return 0; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Bao gồm tệp tiêu đề iostream trong chương trình để sử dụng nó chức năng.
- Đưa tệp tiêu đề vectơ vào chương trình để sử dụng các chức năng của nó.
- Bao gồm không gian tên std trong chương trình vào các lớp của nó mà không cần gọi nó.
- Gọi hàm main(). Logic chương trình nên được thêm vào trong phần thân của nó.
- Tạo một vectơ có tên vec để lưu trữ dữ liệu số nguyên.
- Thêm phần tử 0 vào vectơ có tên vec.
- Thêm phần tử 1 vào vectơ có tên vec.
- Một lời bình luận. Nó sẽ bị bỏ qua bởi C++ trình biên dịch.
- Sử dụng câu lệnh try để bắt ngoại lệ. { Đánh dấu phần bắt đầu của phần thân khối try/catch. Mã được thêm vào trong nội dung sẽ trở thành mã được bảo vệ.
- Hãy thử truy cập phần tử được lưu trữ ở chỉ mục 2 (phần tử thứ ba) của vectơ có tên vec. Phần tử này không tồn tại.
- Kết thúc phần thân của khối try/catch.
- Bắt ngoại lệ. Thông báo lỗi trả về sẽ được lưu trữ trong biến ex.
- In ra một số thông báo trên bảng điều khiển nếu có ngoại lệ.
- Phần cuối của khối bắt.
- Chương trình sẽ trả về một giá trị khi thực hiện thành công.
- Kết thúc phần thân hàm main().
Ví dụ 2:
#include <iostream> using namespace std; double zeroDivision(int x, int y) { if (y == 0) { throw "Division by Zero!"; } return (x / y); } int main() { int a = 11; int b = 0; double c = 0; try { c = zeroDivision(a, b); cout << c << endl; } catch (const char* message) { cerr << message << endl; } return 0; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Bao gồm tệp tiêu đề iostream trong chương trình để sử dụng các chức năng của nó.
- Bao gồm không gian tên std trong chương trình vào các lớp của nó mà không cần gọi nó.
- Tạo một hàm có tên là zeroDivision lấy hai đối số nguyên, x và y. Hàm này sẽ trả về kết quả là double.
- Sử dụng câu lệnh if để kiểm tra xem giá trị của đối số biến y có phải là 0 hay không. { đánh dấu phần bắt đầu của phần thân if.
- Thông báo sẽ được trả lại/ném nếu y bằng 0.
- Kết thúc phần thân của câu lệnh if.
- Hàm zeroDivision sẽ trả về giá trị của x/y.
- Phần cuối của hàm zeroDivision.
- Gọi phương thức main(). { đánh dấu sự bắt đầu của phương thức này.
- Khai báo một biến số nguyên và gán cho nó giá trị 11.
- Khai báo một biến số nguyên b và gán cho nó giá trị 0.
- Khai báo một biến double c và gán giá trị 0 cho nó.
- Sử dụng câu lệnh try để bắt ngoại lệ. { Đánh dấu phần bắt đầu của phần thân khối try/catch. Mã được thêm vào trong nội dung sẽ trở thành mã được bảo vệ.
- Gọi hàm zeroDivision và truyền vào các đối số a và b, tức là 11 và 0. Kết quả của thao tác này sẽ được lưu trong biến c.
- In ra giá trị của biến c trên bàn điều khiển.
- Kết thúc phần thân của khối try/catch.
- Bắt ngoại lệ. Thông báo lỗi trả về sẽ được lưu trữ trong thông báo biến.
- In thông báo lỗi trả về trên bảng điều khiển.
- Phần cuối của khối bắt.
- Chương trình sẽ trả về một giá trị khi thực hiện thành công.
- Kết thúc phần thân hàm main().
C++ Ngoại lệ tiêu chuẩn
C++ đi kèm với một danh sách các ngoại lệ tiêu chuẩn được xác định trong lớp học. Chúng được mô tả dưới đây:
Ngoại lệ | Mô tả |
---|---|
std::ngoại lệ | Đây là một ngoại lệ và là lớp cha của tất cả các tiêu chuẩn C++ các trường hợp ngoại lệ. |
std::bad_alloc | Ngoại lệ này được đưa ra bởi một từ khóa mới. |
std::bad_cast | Đây là một ngoại lệ do Dynamic_cast đưa ra. |
std::bad_Exception | Một công cụ hữu ích để xử lý các trường hợp ngoại lệ không mong muốn trong C++ chương trình. |
std::bad_typeid | Một ngoại lệ được đưa ra bởi typeid. |
std::logic_error | Ngoại lệ này về mặt lý thuyết có thể được phát hiện bằng cách đọc mã. |
std::domain_error | Đây là một ngoại lệ được đưa ra sau khi sử dụng miền không hợp lệ về mặt toán học. |
std::invalid_argument | Một ngoại lệ được đưa ra do sử dụng đối số không hợp lệ. |
std::length_error | Một ngoại lệ được đưa ra sau khi tạo chuỗi std::lớn. |
std::out_of_range | Ném bởi phương pháp. |
std::runtime_error | Đây là một ngoại lệ không thể phát hiện được bằng cách đọc mã. |
std::overflow_error | Ngoại lệ này được đưa ra sau khi xảy ra lỗi tràn toán học. |
std::range_error | Ngoại lệ này được đưa ra khi bạn cố lưu trữ một giá trị ngoài phạm vi. |
std::underflow_error | Một ngoại lệ được đưa ra sau khi xuất hiện dòng chảy toán học. |
Ngoại lệ do người dùng xác định
C++ Lớp std::Exception cho phép chúng ta định nghĩa các đối tượng có thể được ném ra dưới dạng ngoại lệ. Lớp này đã được định nghĩa trong tiêu đề. Lớp cung cấp cho chúng ta một hàm thành viên ảo có tên là what.
Hàm này trả về một chuỗi ký tự kết thúc null thuộc loại char *. Chúng ta có thể ghi đè lên nó trong các lớp dẫn xuất để có mô tả ngoại lệ.
Ví dụ:
#include <iostream> #include <exception> using namespace std; class newException : public exception { virtual const char* what() const throw() { return "newException occurred"; } } newex; int main() { try { throw newex; } catch (exception& ex) { cout << ex.what() << '\n'; } return 0; }
Đầu ra:
Đây là ảnh chụp màn hình của mã:
Giải thích mã:
- Bao gồm tệp tiêu đề iostream trong chương trình của chúng tôi. Chúng tôi sẽ sử dụng các chức năng của nó mà không gặp lỗi.
- Bao gồm tệp tiêu đề ngoại lệ trong chương trình của chúng tôi. Chúng ta sẽ sử dụng các chức năng của nó như thế nào mà không có lỗi.
- Bao gồm không gian tên std trong chương trình của chúng tôi để sử dụng các lớp của nó mà không cần gọi nó.
- Tạo một lớp mới có tên newException. Lớp này kế thừa lớp ngoại lệ của C++.
- Sự khởi đầu của cơ thể lớp học.
- Ghi đè hàm thành viên ảo what() được xác định trong tệp tiêu đề ngoại lệ. Sau đó chúng ta sẽ mô tả ngoại lệ của chính chúng ta, ngoại lệ mới.
- Bắt đầu định nghĩa ngoại lệ mới.
- Thông báo sẽ được trả về nếu ngoại lệ mới bị bắt.
- Kết thúc định nghĩa của ngoại lệ mới.
- Kết thúc phần thân của lớp newException. newex là tên được sử dụng để bắt ngoại lệ mới của chúng ta, sau đó newException sẽ được gọi.
- Gọi hàm main(). Logic chương trình nên được thêm vào trong phần thân của nó. { đánh dấu sự bắt đầu của phần thân của nó.
- Sử dụng câu lệnh try để đánh dấu đoạn mã mà chúng ta cần đánh dấu ngoại lệ. { Đánh dấu phần bắt đầu của phần thân khối try/catch. Mã được bao quanh bởi điều này sẽ được bảo vệ.
- Ném ngoại lệ newex nếu nó bị bắt.
- Kết thúc phần thử.
- Sử dụng câu lệnh bắt để bắt ngoại lệ. Thông báo lỗi ngoại lệ sẽ được lưu trữ trong biến ex.
- In thông báo lỗi ngoại lệ trên bảng điều khiển.
- Kết thúc phần thân của câu lệnh Catch.
- Chương trình sẽ trả về một giá trị nếu nó thực thi thành công.
- Phần cuối của hàm main().
Tổng kết
- Với việc xử lý ngoại lệ trong C++, bạn có thể xử lý các lỗi thời gian chạy.
- Lỗi thời gian chạy là lỗi xảy ra trong quá trình thực hiện chương trình.
- Xử lý ngoại lệ giúp bạn xử lý mọi tình huống bất ngờ trong chương trình của mình.
- Khi tình huống bất ngờ xảy ra, quyền điều khiển chương trình sẽ được chuyển giao cho người xử lý.
- Để bắt ngoại lệ, bạn đặt một đoạn mã bên dưới khối try-catch.
- Từ khóa ném giúp chương trình ném ngoại lệ, giúp chương trình xử lý vấn đề.
- Từ khóa try giúp xác định khối mã mà một số ngoại lệ nhất định sẽ được kích hoạt.
- Chúng ta có thể ghi đè hàm what() của tệp tiêu đề ngoại lệ để xác định các ngoại lệ của mình.