C++ Xử lý ngoại lệ: Ví dụ thử, bắt, ném

⚡ Tóm tắt thông minh

Xử lý ngoại lệ trong C++ Cho phép chương trình phát hiện và xử lý lỗi thời gian chạy bằng cách sử dụng try, catch và throw, để tránh bị sập. Ở đây bạn sẽ học các từ khóa, cú pháp, các ngoại lệ chuẩn và ngoại lệ do người dùng định nghĩa với các ví dụ.

  • ⚠️ Những gì nó là: Xử lý ngoại lệ giúp bắt các lỗi xảy ra trong quá trình thực thi để chương trình có thể phục hồi.
  • 🔑 Từ khóa: Nó sử dụng try để kiểm tra mã, throw để báo lỗi và catch để xử lý lỗi.
  • 🧾 Cú pháp: Đặt đoạn mã tiềm ẩn rủi ro vào khối try và xử lý lỗi trong khối catch.
  • 📚 Các trường hợp ngoại lệ thông thường: C++ Cung cấp các ngoại lệ tích hợp sẵn trong tiêu đề ngoại lệ.
  • 🤖 Hỗ trợ từ AI: Các công cụ AI như GitHub Copilot bổ sung thêm các khối try-catch và xử lý lỗi.

C++ Xử lý ngoại lệ

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:

Từ khóa xử lý ngoại lệ

Đây là ảnh chụp màn hình của mã:

Từ khóa xử lý ngoại lệ

Code Giải thích:

  1. Bao gồm tệp tiêu đề iostream trong chương trình để sử dụng nó chức năng.
  2. Đưa tệp tiêu đề vectơ vào chương trình để sử dụng các chức năng của nó.
  3. 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ó.
  4. 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ó.
  5. Tạo một vectơ có tên vec để lưu trữ dữ liệu số nguyên.
  6. Thêm phần tử 0 vào vectơ có tên vec.
  7. Thêm phần tử 1 vào vectơ có tên vec.
  8. Một lời bình luận. Nó sẽ bị bỏ qua bởi C++ trình biên dịch.
  9. 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ệ.
  10. 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.
  11. Kết thúc phần thân của khối try/catch.
  12. Bắt ngoại lệ. Thông báo lỗi trả về sẽ được lưu trữ trong biến ex.
  13. In ra một số thông báo trên bảng điều khiển nếu có ngoại lệ.
  14. Phần cuối của khối bắt.
  15. Chương trình sẽ trả về một giá trị khi thực hiện thành công.
  16. 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:

Từ khóa xử lý ngoại lệ

Đây là ảnh chụp màn hình của mã:

Từ khóa xử lý ngoại lệ

Code Giải thích:

  1. 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ó.
  2. 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ó.
  3. 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.
  4. 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.
  5. Thông báo sẽ được trả lại/ném nếu y bằng 0.
  6. Kết thúc phần thân của câu lệnh if.
  7. Hàm zeroDivision sẽ trả về giá trị của x/y.
  8. Phần cuối của hàm zeroDivision.
  9. Gọi phương thức main(). { đánh dấu sự bắt đầu của phương thức này.
  10. Khai báo một biến số nguyên và gán cho nó giá trị 11.
  11. Khai báo một biến số nguyên b và gán cho nó giá trị 0.
  12. Khai báo một biến double c và gán giá trị 0 cho nó.
  13. 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ệ.
  14. 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.
  15. In ra giá trị của biến c trên bàn điều khiển.
  16. Kết thúc phần thân của khối try/catch.
  17. 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.
  18. In thông báo lỗi trả về trên bảng điều khiển.
  19. Phần cuối của khối bắt.
  20. Chương trình sẽ trả về một giá trị khi thực hiện thành công.
  21. Kết thúc phần thân hàm main().

C++ Ngoại lệ tiêu chuẩn

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ả Chi tiế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:

Ngoại lệ do người dùng xác định

Đây là ảnh chụp màn hình của mã:

Ngoại lệ do người dùng xác định

Code Giải thích:

  1. 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.
  2. 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.
  3. 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ó.
  4. 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++.
  5. Sự khởi đầu của cơ thể lớp học.
  6. 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.
  7. Bắt đầu định nghĩa ngoại lệ mới.
  8. Thông báo sẽ được trả về nếu ngoại lệ mới bị bắt.
  9. Kết thúc định nghĩa của ngoại lệ mới.
  10. 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.
  11. 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ó.
  12. 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ệ.
  13. Ném ngoại lệ newex nếu nó bị bắt.
  14. Kết thúc phần thử.
  15. 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.
  16. In thông báo lỗi ngoại lệ trên bảng điều khiển.
  17. Kết thúc phần thân của câu lệnh Catch.
  18. Chương trình sẽ trả về một giá trị nếu nó thực thi thành công.
  19. Phần cuối của hàm main().

Câu Hỏi Thường Gặp

Xử lý ngoại lệ là một cách để phát hiện và phản hồi các lỗi xảy ra trong quá trình thực thi. C++ Sử dụng các từ khóa try, throw và catch để chương trình có thể phục hồi thay vì bị lỗi.

C++ Nó sử dụng ba từ khóa: try bao bọc đoạn mã có thể gây lỗi, throw ném ra một ngoại lệ khi xảy ra lỗi và catch xử lý ngoại lệ được ném ra.

Đặt đoạn mã tiềm ẩn rủi ro vào trong khối try, sau đó thêm một hoặc nhiều khối catch, mỗi khối xử lý một loại ngoại lệ cụ thể được ném ra từ khối try.

Các ngoại lệ chuẩn là các lớp ngoại lệ được tích hợp sẵn trong tệp tiêu đề ngoại lệ, chẳng hạn như std::bad_alloc và std::out_of_range, dùng để báo cáo các lỗi thường gặp khi chạy chương trình.

Ngoại lệ do người dùng định nghĩa là một lớp tùy chỉnh, thường được kế thừa từ std::exception, ghi đè hàm what() để mô tả điều kiện lỗi cụ thể của riêng bạn.

Các trợ lý AI như GitHub Copilot sẽ bao bọc đoạn mã tiềm ẩn rủi ro trong các khối try-catch, tạo ra các lớp ngoại lệ tùy chỉnh và đề xuất những ngoại lệ cần bắt khi bạn gõ.

Đúng vậy. Các công cụ hỗ trợ bởi AI phát hiện các ngoại lệ chưa được xử lý, đề xuất các khối bắt lỗi cụ thể thay vì các khối chung chung và thêm các thông báo lỗi có ý nghĩa, giúp bạn... C++ Mã nguồn mạnh mẽ hơn.

Phương thức `throw` sẽ ném ra một ngoại lệ khi phát hiện lỗi, trong khi phương thức `catch` sẽ nhận ngoại lệ đó và chạy đoạn mã xử lý hoặc báo cáo lỗi.

Tóm tắt bài viết này với: