cơ chế bắt lỗi trong java và c++

20
BÁO CÁO CƠ CHẾ BT LI TRONG JAVA VÀ C++ 1 MC LC I. Gii thiu: .............................................................................................................. 2 II. Mục đích: ................................................................................................................ 2 III. Cơ chế bt li trong Java và C++: .............................................................. 2 1. Cơ chế bt li trong Java: ................................................................................... 2 1.1. Xlý ngoi ltrong Java:.............................................................................. 2 1.2. Mô hình xlý ngoi ltrong Java: ............................................................... 2 1.2.1. Các ưu điểm của mô hình “catch và throw”:.............................................. 3 1.2.2. Các khối “try” và “catch”: ......................................................................... 3 1.3. Các khi cha nhiều “catch”: ....................................................................... 5 1.4. Khối “finally”: ................................................................................................ 7 1.5. Các ngoi lđược định nghĩa với lệnh “throw” và “throws”: .................... 9 1.6. Danh sách các ngoi l: ............................................................................... 10 2. Cơ chế bt li trong C++: ................................................................................... 11 2.1. Xlý li: ....................................................................................................... 11 2.1.1. Xlý li truyn thng: ............................................................................... 12 2.1.2. Hn chế ca xlý li truyn thng: .......................................................... 12 2.2. Ngoi ltrong C++: ..................................................................................... 12 2.3. Các kiu ngoi ltrong C++:....................................................................... 13 2.4. Cơ chế ngoi ltrong C++: ......................................................................... 13 2.4.1. Quy trình gi hàm và trvtrong trường hợp bình thường: .................... 13 2.4.2. Quy trình ném và bt ngoi l: .................................................................. 14 2.4.3. Nếu mt hàm không thbt ngoi l: ........................................................ 14 2.4.4. Nếu không có hàm nào bắt được ngoi l: ................................................ 15 2.5. Cú pháp xlý ngoi ltrong C++: .............................................................. 15 2.5.1. Ném ngoi l(throw): ................................................................................ 15 2.5.2. Khi try-catch: ........................................................................................... 16 2.6. So khp ngoi ltrong C++: ....................................................................... 17 2.7. Lp Exception trong C++: ........................................................................... 18

Upload: suri-ken

Post on 31-Dec-2015

301 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

1

MỤC LỤC

I. Giới thiệu: .............................................................................................................. 2

II. Mục đích: ................................................................................................................ 2

III. Cơ chế bắt lỗi trong Java và C++: .............................................................. 2

1. Cơ chế bắt lỗi trong Java: ................................................................................... 2

1.1. Xử lý ngoại lệ trong Java: .............................................................................. 2

1.2. Mô hình xử lý ngoại lệ trong Java: ............................................................... 2

1.2.1. Các ưu điểm của mô hình “catch và throw”:.............................................. 3

1.2.2. Các khối “try” và “catch”: ......................................................................... 3

1.3. Các khối chứa nhiều “catch”: ....................................................................... 5

1.4. Khối “finally”: ................................................................................................ 7

1.5. Các ngoại lệ được định nghĩa với lệnh “throw” và “throws”: .................... 9

1.6. Danh sách các ngoại lệ: ............................................................................... 10

2. Cơ chế bắt lỗi trong C++: ................................................................................... 11

2.1. Xử lý lỗi: ....................................................................................................... 11

2.1.1. Xử lý lỗi truyền thống: ............................................................................... 12

2.1.2. Hạn chế của xử lý lỗi truyền thống: .......................................................... 12

2.2. Ngoại lệ trong C++: ..................................................................................... 12

2.3. Các kiểu ngoại lệ trong C++:....................................................................... 13

2.4. Cơ chế ngoại lệ trong C++: ......................................................................... 13

2.4.1. Quy trình gọi hàm và trả về trong trường hợp bình thường: .................... 13

2.4.2. Quy trình ném và bắt ngoại lệ: .................................................................. 14

2.4.3. Nếu một hàm không thể bắt ngoại lệ: ........................................................ 14

2.4.4. Nếu không có hàm nào bắt được ngoại lệ: ................................................ 15

2.5. Cú pháp xử lý ngoại lệ trong C++: .............................................................. 15

2.5.1. Ném ngoại lệ (throw): ................................................................................ 15

2.5.2. Khối try-catch: ........................................................................................... 16

2.6. So khớp ngoại lệ trong C++: ....................................................................... 17

2.7. Lớp Exception trong C++: ........................................................................... 18

Page 2: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

2

I. Giới thiệu:

Exception là một lỗi đặc biệt. Lỗi này xuất hiện vào lúc thực thi chương trình.

Các trạng thái không bình thường xảy ra trong khi thi hành chương trình tạo ra các

exception. Những trạng thái này không được biết trước trong khi ta đang xây dựng

chương trình. Nếu không phân phối các trạng thái này thì exception có thể bị kết

thúc đột ngột.

II. Mục đích:

Một chương trình nên có cơ chế xử lý ngoại lệ thích hợp. Nếu không, chương

trình sẽ bị ngắt khi một exception xảy ra. Trong trường hợp đó, tất cả các nguồn tài

nguyên mà hệ thống trước kia phân phối sẽ được di dời trong cùng trạng thái. Điều

này gây lãng phí tài nguyên. Để tránh trường hợp này, tất cả các nguồn tài nguyên

mà hệ thống phân phối nên được thu hồi lại. Tiến trình này đòi hỏi cơ chế xử lý

ngoại lệ thích hợp.

Cho ví dụ, xét thao tác nhập xuất (I/O) trong một tập tin. Nếu việc chuyển đổi

kiểu dữ liệu không thực hiện đúng, một ngoại lệ sẽ xảy ra và chương trình bị hủy

mà không đóng tập tin lại. Lúc đó tập tin dễ bị hư hại và các nguồn tài nguyên được

cấp phát cho tập tin không được thu hồi lại cho hệ thống.

III. Cơ chế bắt lỗi trong Java và C++:

1. Cơ chế bắt lỗi trong Java:

1.1. Xử lý ngoại lệ trong Java:

Khi một ngoại lệ xảy ra, đối tượng tương ứng với ngoại lệ đó được tạo ra. Đối

tượng này sau đó được truyền cho phương thức là nơi mà ngoại lệ xảy ra. Đối tượng

này chứa thông tin chi tiết về ngoại lệ. Thông tin này có thể được nhận về và được

xử lý. Các môi trường runtime như “IllegalAccessException”,

“EmptyStackException” v.v… có thể chặn được các ngoại lệ. Đoạn mã trong

chương trình đôi khi có thể tạo ra các ngoại lệ. Lớp “throwable” được Java cung

cấp là lớp trên nhất của lớp Exception, lớp này là lớp cha của các ngoại lệ khác

nhau.

1.2. Mô hình xử lý ngoại lệ trong Java:

Trong Java, mô hình xử lý ngoại lệ kiểm tra việc xử lý những hiệu ứng lề (lỗi),

được biết đến là mô hình “catch và throw”. Trong mô hình này, khi một lỗi xảy ra,

một ngoại lệ sẽ bị chặn và được đưa vào trong một khối. Người lập trình viên nên

xét các trạng thái ngoại lệ độc lập nhau từ việc điều khiển thông thường trong

chương trình. Các ngoại lệ phải được bắt giữ nếu không chương trình sẽ bị ngắt.

HNhan
Highlight
HNhan
Highlight
HNhan
Highlight
Page 3: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

3

Ngôn ngữ Java cung cấp 5 từ khóa sau để xử lý các ngoại lệ:

try

catch

throw

throws

finally

Dưới đây là cấu trúc của mô hình xử lý ngoại lệ:

try {

// code dự kiến sẽ xuất hiện ngoại lệ

} catch(Exception e1) {

// Nếu phát hiện 1 ngoại lệ trong khối try thuộc e1 thì thực hiện xử lý

// ngoại lệ tại đây nếu không thì xét đến khối “catch” tiếp theo.

} catch(Exception e2) {

// Tương tự khối catch thứ nhất

} catch(Exception eN) {

// Tương tự khối catch thứ nhất

} finally {

// Luôn thực thi khối lệnh này dù có hay không ngoại lệ xảy ra

}

1.2.1. Các ưu điểm của mô hình “catch và throw”:

Mô hình “catch và throw” có hai ưu điểm:

Người lập trình viên phải phân phối trạng thái lỗi chỉ vào những nơi cần

thiết. Không cần phải thực hiện tại mọi mức.

Một thông báo lỗi có thể được in ra khi tiến hành xử lý ngoại lệ.

1.2.2. Các khối “try” và “catch”:

Khối “try-catch” được sử dụng để thi hành mô hình “catch và throw” của việc

xử lý ngoại lệ. Khối “try” chứa một bộ các lệnh có thể thi hành được. Các ngoại lệ

có thể bị chặn khi thi hành những câu lệnh này. Phương thức dùng để chặn ngoại lệ

có thể được khai báo trong khối “try”. Một hay nhiều khối “catch” có thể theo sau

khối “try”. Các khối “catch” này bắt các ngoại lệ bị chặn trong khối “try”. Hãy nhìn

khối “try” dưới đây:

HNhan
Highlight
HNhan
Highlight
HNhan
Highlight
HNhan
Highlight
HNhan
Highlight
Page 4: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

4

public class ChiaCho0Demo {

public static void main(String args[]){

try {

int num = calculate(9,0);

System.out.println(num);

} catch(Exception e) {

System.err.println("Co loi xay ra: " + e.toString());

}

}

static int calculate(int no, int no1){

int num = no / no1;

return num;

}

}

Ở đây, “e” là đối tượng của lớp “Exception”. Chúng ta có thể sử dụng đối

tượng này để in các chi tiết về ngoại lệ. Phương thức “toString” được sử dụng để

mô tả exception phát sinh ra. Hình sau chỉ ra kết xuất của phương thức “toString()”.

Để bắt giữ bất cứ ngoại lệ nào, ta phải chỉ ra kiểu ngoại lệ là “Exception”.

catch(Exception e)

Page 5: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

5

Khi ngoại lệ bị bắt giữ không biết thuộc kiểu nào, chúng ta có thể sử dụng lớp

“Exception” để bắt ngoại lệ đó.

1.3. Các khối chứa nhiều “catch”:

Các khối chứa nhiều “catch” xử lý các kiểu ngoại lệ khác nhau một cách độc

lập. Chúng được liệt kê trong đoạn mã sau:

public class ExceptionTest1 {

public static void main(String args[]) throws ExecutionException {

try {

System.out.print("Nhap canh hinh vuong:");

Scanner num = new Scanner(System.in);

int numValue = num.nextInt();

System.out.println("Dien tich hinh vuong la: " + numValue

* numValue);

} catch (InputMismatchException e2) {

System.out.println("Dau vao khong hop le!");

} catch (Exception e) {

System.out.println(e.toString());

}

}

}

Trong trường hợp này, khối “catch” đầu tiên sẽ bắt giữ một

“InputMismatchException”. Khối “catch” thứ hai sẽ xử lý kiểu ngoại lệ khác với

khối “catch” thứ nhất. Và đây là kết quả của chương trình trên:

HNhan
Highlight
Page 6: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

6

Một chương trình cũng có thể chứa các khối “try” lồng nhau. Ví dụ đoạn mã

dưới đây:

try {

// Đoạn mã có thể gây ra IOException

try {

// Đoạn mã có thể gây ra NumberFormatException

} catch (NumberFormatException e1) {

// Xử lý lỗi sai định dạng số

}

} catch (IOException e2) {

// Xử lý lỗi vào ra

}

Page 7: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

7

Khi sử dụng các “try” lồng nhau, khối “try” bên trong được thi hành đầu tiên.

Bất kì ngoại lệ nào bị chặn trong khối “try” sẽ bị bắt giữ trong các khối “catch” theo

sau. Nếu khối “catch” thích hợp không được tìm thấy thì các khối “catch” của các

khối “try” bên ngoài sẽ được xem xét. Nếu không, Java Runtime Environment xử

lý các ngoại lệ.

1.4. Khối “finally”:

Khi một ngoại lệ xuất hiện, phương thức đang được thực thi có thể bị dừng mà

không được thi hành toàn vẹn. Nếu điều này xảy ra, thì các đoạn mã (ví dụ như đoạn

mã với chức năng thu hồi tài nguyên có các lệnh đóng lại tập tin khai báo cuối

phương thức) sẽ không bao giờ được gọi. Java cung cấp khối “finally” để giải quyết

việc này. Khối “finally” thực hiện tất cả các việc thu dọn cho một ngoại lệ xảy ra.

Khối này có thể được sử dụng kết hợp với khối “try”. Khối “finally” chứa các câu

lệnh thu hồi tài nguyên về cho hệ thống hay lệnh in ra các câu thông báo. Các lệnh

này bao gồm:

Đóng tập tin.

Đóng lại bộ kết quả (được sử dụng trong chương trình cơ sở dữ liệu).

Đóng lại các kết nối được tạo trong cơ sở dữ liệu.

try {

doSomethingThatMightThrowAnException();

} finally {

cleanup();

}

Phương thức “cleanup()” được gọi nếu phương thức

“doSomethingThatMightThrowAnException()” chặn một ngoại lệ. Mặt khác

“cleanup” cũng được gọi ngay khi không có ngoại lệ nào bị chặn và thi hành tiếp

tục sau khối lệnh “finally”.

Khối lệnh “finally” là tùy ý, không bắt buộc. Khối này được đặt sau khối

“catch”. Hệ thống sẽ duyệt từ câu lệnh đầu tiên của khối “finally” sau khi gặp câu

lệnh “return” hay lệnh “break” được dùng trong khối “try”.

Khối “finally” đảm bảo lúc nào cũng được thực thi, bất chấp có ngoại lệ xảy

ra hay không.

Hình dưới đây minh họa sự thi hành của các khối “try”, “catch” và “finally”:

HNhan
Highlight
HNhan
Highlight
HNhan
Highlight
HNhan
Highlight
Page 8: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

8

Ta xét ví dụ sau đây:

public class ExceptionTest2 {

static String str;

public static void main(String s[]) {

try {

System.out.println("Truoc ngoai le");

staticLengthmethod();

System.out.println("Sau ngoai le");

} catch (NullPointerException ne) {

System.out.println("Da xay ra loi");

} finally {

System.out.println("Trong finally");

}

}

static void staticLengthmethod() {

System.out.println(str.length());

}

}

Page 9: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

9

Và đây là kết quả khi chạy chương trình:

Trong ví dụ này, câu lệnh trong khối “finally” luôn luôn thi hành, bất chấp

ngoại lệ có xảy ra hay không. Trong kết xuất trên, khối “finally” vẫn được thi hành

mặc dù ngoại lệ vẫn xảy ra.

1.5. Các ngoại lệ được định nghĩa với lệnh “throw” và “throws”:

Các ngoại lệ bị chặn với sự trợ giúp của các từ khóa “throw”. Từ khóa “throw”

chỉ ra một ngoại lệ vừa xảy ra. Toán tử của “throw” là một đối tượng của lớp, lớp

này được dẫn xuất từ “throwable”.

Một phương thức đơn có thể chặn nhiều ngoại lệ. Để xử lý những ngoại lệ này,

ta cần cung cấp một danh sách các ngoại lệ mà phương thức chăn trong phần định

nghĩa của phương thức. Giả sử rằng phương thức “x()” gọi phương thức “y()”.

Phương thức “y()” chặn một ngoại lệ không được xử lý. Trong trường hợp này,

phương thức gọi “x()” nên khai báo việc chặn cùng một ngoại lệ với phương thức

được gọi “y()”. Ta nên khai báo khối “try-catch” trong phương thức “x()” để đảm

bảo rằng ngoại lệ không được truyền cho các phương thức mà gọi phương thức này.

Đoạn lệnh sau chỉ cách sử dụng của lệnh “throw”:

public class ExceptionTest3 {

public static void main(String args[]) {

try {

int num = calculate(9, 3);

System.out.println("Lan 1: " + num);

HNhan
Highlight
HNhan
Highlight
Page 10: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

10

num = calculate(9, 0);

System.out.println("Lan 2: " + num);

} catch (Exception e) {

System.out.println(e.getMessage());

}

}

static int calculate(int no, int no1) throws ArithmeticException {

if (no1 == 0)

throw new ArithmeticException("Khong the chia cho 0!");

int num = no / no1;

return num;

}

}

Trong ví dụ trên, phương thức “calculate” được khai báo từ khóa “throws”. Từ

khoá này được theo sau bởi các ngoại lệ mà phương thức này có thể chặn, trong

trường hợp này là “ArithmeticException”.

1.6. Danh sách các ngoại lệ:

Bảng sau đây liệt kê một số ngoại lệ:

Ngoại lệ Lớp cha của thứ tự phân cấp ngoại lệ

RuntimeException Lớp cơ sở cho nhiều ngoại lệ java.lang

ArthmeticException Trạng thái lỗi về số

IllegalAccessException Lớp không thể truy cập.

IllegalArgumentException Phương thức nhận một đối số không hợp

lệ

ArrayIndexOutOfBoundsException Kích thước của mảng lớn hơn 0 hay lớn

hơn kích thước thật sự của mảng

NullPointerException Khi muốn truy cập đối tượng null

SecurityException Việc thiết lập cơ chế bảo mật không

được hoạt động

ClassNotFoundException Không thể nạp lớp yêu cầu

NumberFormatException Việc chuyển đối số không thành công từ

chuỗi sang số thực

AWTException Ngoại lệ về AWT

HNhan
Highlight
Page 11: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

11

IOException Lớp cha của các ngoại lệ I/O

FileNotFoundException Không thể định vị tập tin

EOFException Kết thúc một tập tin

NoSuchMethodException Phương thức yêu cầu không tồn tại

InterruptedException Khi một luồng bị ngắt

Tóm tắt:

Bất cứ khi nào một lỗi xuất hiện trong khi thi hành chương trình, nghĩa là

một ngoại lệ đã xuất hiện.

Ngoại lệ phát sinh vào lúc thực thi chương trình theo trình tự mã.

Mỗi ngoại lệ phát sinh ra phải bị bắt giữ, nếu không ứng dụng sẽ bị ngắt.

Việc sử lý ngoại lệ cho phép bạn kết hợp tất cả tiến trình xử lý lỗi trong

một nơi. Lúc đó đoạn mã của bạn sẽ rõ ràng hơn.

Java sử dụng khối “try - catch” để xử lý các ngoại lệ. Các câu lệnh trong

khối “try” chặn ngoại lệ, còn khối “catch” xử lý ngoại lệ.

Các khối chứa nhiều “catch” có thể được sử dụng để xử lý các kiểu ngoại

lệ khác theo cách khác nhau.

Từ khóa “throw” liệt kê các ngoại lệ mà phương thức chặn.

Từ khóa “throw” chỉ ra một ngoại lệ vừa xuất hiện.

Khối “finally” khai báo các câu lệnh trả về nguồn tài nguyên cho hệ thống

và in những câu thông báo.

2. Cơ chế bắt lỗi trong C++:

2.1. Xử lý lỗi:

Chương trình nào cũng có khả năng gặp phải các tình huống không mong

muốn. Có thể do những nguyên nhân sau đây:

Người dùng nhập dữ liệu không hợp lệ,

Đĩa cứng bị đầy,

File cần mở bị khóa,

Đối số cho hàm không hợp lệ,...

Xử lý như thế nào?

Một chương trình không quan trọng có thể dừng lại,

Chương trình điều khiển không lưu? Điều khiển máy bay?

Đoạn chương trình xử lý lỗi cơ bản:

double MyDivide(double numerator, double denominator) {

if (denominator == 0.0) {

HNhan
Highlight
Page 12: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

12

printf("Loi! Mau so khong the bang 0\n");

exit(0);

}

else {

return numerator / denominator;

}

}

Mã thư viện (nơi gặp lỗi) thường không có đủ thông tin để xử lý lỗi. Do vậy,

cần có cơ chế để mã thư viện báo cho mã ứng dụng rằng nó vì một lý do nào đó

không thể tiếp tục chạy được, để mã ứng dụng xử lý tùy theo tình huống.

2.1.1. Xử lý lỗi truyền thống:

Xử lý lỗi truyền thống thường là mỗi hàm lại thông báo trạng thái thành công/thất

bại qua một mã lỗi. Chẳng hạn:

Biến toàn cục (chẳng hạn error).

Giá trị trả về.

int remove(const char *filename);

Tham số phụ là tham chiếu

double MyDivide(double numerator, double denominator, int &status);

2.1.2. Hạn chế của xử lý lỗi truyền thống:

Phải có lệnh kiểm tra lỗi sau mỗi lời gọi hàm → code trông rối rắm, dài, khó

đọc,

Lập trình viên ứng dụng quên kiểm tra, hoặc cố tình bỏ qua:

Bản chất con người,

Lập trình viên ứng dụng thường không có kinh nghiệm bằng lập trình

viên thư viện.

Rắc rối khi đẩy thông báo lỗi từ hàm được gọi sang hàm gọi vì từ một hàm

ta chỉ có thể trả về một kiểu thông báo lỗi.

2.2. Ngoại lệ trong C++:

Ngoại lệ là cơ chế thông báo và xử lý lỗi giải quyết được các vấn đề kể trên.

Tách được phần xử lý lỗi ra khỏi phần thuật toán chính.

Cho phép 1 hàm thông báo về nhiều loại ngoại lệ. Không phải hàm nào cũng

phải xử lý lỗi nếu có một số hàm gọi thành chuỗi, ngoại lệ chỉ lần được xử

lý tại một hàm là đủ.

Page 13: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

13

Không thể bỏ qua ngoại lệ, nếu không, chương trình sẽ kết thúc.

→ Cơ chế ngoại lệ mềm dẻo hơn kiểu xử lý lỗi truyền thống.

2.3. Các kiểu ngoại lệ trong C++:

Một ngoại lệ là một đối tượng chứa thông tin về một lỗi và được dùng để truyền

thông tin đó tới cấp thực thi cao hơn.

Ngoại lệ có thể thuộc kiểu dữ liệu bất kỳ của C++:

Kiểu dữ liệu có sẵn, chẳng hạn: int, char*,…

Kiểu dữ liệu người dùng tự định nghĩa (thường dùng).

Các lớp ngoại lệ trong thư viện <exception>.

2.4. Cơ chế ngoại lệ trong C++:

Quá trình truyền ngoại lệ từ ngữ cảnh thực thi hiện hành tới mức thực thi cao

hơn gọi là ném một ngoại lệ (throw an exception).

Vị trí trong mã của hàm nơi ngoại lệ được ném được gọi là điểm ném (throw

point).

Khi một ngữ cảnh thực thi tiếp nhận và truy nhập một ngoại lệ, nó được coi

là bắt ngoại lệ (catch the exception).

2.4.1. Quy trình gọi hàm và trả về trong trường hợp bình thường:

void main() {

int x, y;

Page 14: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

14

cout << "Nhap 2 so:";

cin >> x >> y;

cout << "Ket qua chia so thu nhat cho thu hai: ";

cout << MyDivide(x, y) << "\n";

}

2.4.2. Quy trình ném và bắt ngoại lệ:

Giả sử người dùng nhập mẫu số bằng 0.

Mã chương trình trong MyDivide() tạo một ngoại lệ (bằng cách nào đó) và

ném.

Khi một hàm ném một ngoại lệ, nó lập tức kết thúc thực thi và gửi ngoại lệ

đó cho nơi gọi nó.

main() sẽ bắt và giải quyết ngoại lệ. Chẳng hạn yêu cầu người dùng nhập lại

mẫu số.

2.4.3. Nếu một hàm không thể bắt ngoại lệ:

Page 15: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

15

Giả sử hàm MyLazyDivide() không thể bắt ngoại lệ do MyDivide() ném.

Không phải hàm nào bắt được ngoại lệ cũng có thể bắt được mọi loại

ngoại lệ.

Chẳng hạn hàm f() bắt được các ngoại lệ loại E1 nhưng không bắt

được các ngoại lệ loại E2.

Ngoại lệ đó sẽ được chuyển lên mức trên cho main() bắt.

2.4.4. Nếu không có hàm nào bắt được ngoại lệ:

Nếu có một ngoại lệ được ném, nó sẽ được chuyển qua tất cả các hàm.

Tại mức thực thi cao nhất, chương trình tổng (nơi gọi hàm main()) sẽ bắt mọi

ngoại lệ còn sót lại mà nó nhìn thấy.

Khi đó, chương trình lập tức kết thúc.

2.5. Cú pháp xử lý ngoại lệ trong C++:

Cơ chế xử lý ngoại lệ của C++ có 3 tính năng chính:

Khả năng tạo và ném ngoại lệ (sử dụng từ khoá throw).

Khả năng tách logic xử lý ngoại lệ trong một hàm ra khỏi phần còn lại của

hàm (sử dụng từ khoá try).

Khả năng bắt và giải quyết ngoại lệ (sử dụng từ khoá catch).

2.5.1. Ném ngoại lệ (throw):

Để ném một ngoại lệ, ta dùng từ khoá throw, kèm theo đối tượng mà ta định

ném: throw <object>;

Ta có thể dùng mọi thứ làm ngoại lệ, kể cả giá trị thuộc kiểu dữ liệu có sẵn:

throw 15;

throw MyObj(…);

Ví dụ, MyDivide() ném ngoại lệ là một string:

double MyDivide(double numerator, double denominator) {

if (denominator == 0.0) {

throw string("Loi! Mau so khong the bang 0");

exit(0);

} else {

return numerator / denominator;

}

}

Trong trường hợp cần cung cấp nhiều thông tin hơn cho hàm gọi, ta tạo một

class dành riêng cho các ngoại lệ:

class MyException {

int a, b;

public:

MyException(int a, int b);

Page 16: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

16

~MyException();

int getA();

int getB();

};

int x, y;

...

if (...) throw MyException(x, y);

...

2.5.2. Khối try-catch:

Khối try-catch dùng để:

Tách phần giải quyết lỗi ra khỏi phần có thể sinh lỗi.

Quy định các loại ngoại lệ được bắt tại mức thực thi hiện hành.

Cú pháp chung cho khối try-catch:

try {

// Code that could generate an exception

}

catch (<Type of exception>) {

// Code that resolves an exception of that type

};

Mã liên quan đến thuật toán nằm trong khối try,

Mã giải quyết lỗi đặt trong (các) khối catch.

Có thể có nhiều khối catch, mỗi khối chứa mã để giải quyết một loại ngoại

lệ cụ thể:

try {

// Code that could generate an exception

}

catch (<exception type1>) {

// Code that resolves a type1 exception

}

catch (<exception type2>) {

// Code that resolves a type2 exception

}

...

catch (<exception typeN>) {

// Code that resolves a typeN exception

};

Dấu chấm phẩy đánh dấu kết thúc của toàn khối try-catch.

Ví dụ:

void main() {

int x, y;

double result;

Page 17: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

17

cout << "Nhap 2 so:";

cin >> x >> y;

try {

result = MyDivide(x, y);

}

catch (string &s) {

//resolve error

};

cout << "Ket qua chia so thu nhat cho thu hai: ";

cout << result << "\n";

}

→ MyDevide ném ngoại lệ là một string,

→ Giải quyết lỗi?

Giải quyết lỗi:

void main() {

int x, y;

double result;

bool success;

do {

success = true;

cout << "Nhap 2 so:";

cin >> x >> y;

try {

result = MyDivide(x, y);

}

catch (string& s) {

cout << s << endl;

success = false;

};

} while (success == false);

cout << "Ket qua chia so thu nhat cho thu hai: ";

cout << result << "\n";

}

2.6. So khớp ngoại lệ trong C++:

Khi một ngoại lệ được ném từ trong một khối try, hệ thống xử lý ngoại lệ sẽ

kiểm tra các kiểu được liệt kê trong khối catch theo thứ tự liệt kê:

Khi tìm thấy kiểu ăn khớp, ngoại lệ được coi là được giải quyết, không

cần tiếp tục tìm kiếm,

Nếu không tìm thấy, mức thực thi hiện hành bị kết thúc, ngoại lệ được

chuyển lên mức cao hơn.

Page 18: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

18

Khi tìm các kiểu dữ liệu khớp với ngoại lệ, trình biên dịch nói chung sẽ không

thực hiện đổi kiểu tự động:

Nếu một ngoại lệ kiểu float được ném, nó sẽ không khớp với một khối

catch cho ngoại lệ kiểu int.

Một đối tượng hoặc tham chiếu kiểu dẫn xuất sẽ khớp với một lệnh catch

dành cho kiểu cơ sở:

Nếu một ngoại lệ kiểu Car được ném, nó sẽ khớp với một khối catch

cho ngoại lệ kiểu Vehicle:

try {…}

catch (Vehicle &vehicle) {…}

catch (Car &c) {…}

catch (Truck &t) {…};

Mọi ngoại lệ là đối tượng được sinh từ cây Vehicle sẽ khớp lệnh catch

đầu tiên (các lệnh còn lại sẽ không bao giờ chạy).

Nếu muốn bắt các ngoại lệ dẫn xuất tách khỏi ngoại lệ cơ sở, ta phải xếp lệnh

catch cho lớp dẫn xuất lên trước:

try {…}

catch (Car &c) {…}

catch (Truck &t) {…}

catch (Vehicle &vehicle) {…};

Nếu muốn bắt tất cả các ngoại lệ được ném, ta đặt dấu ba chấm bên trong

lệnh catch:

catch (...) {…};

Do tham số ba chấm bắt được mọi ngoại lệ, ta chỉ nên sử dụng nó cho lệnh

catch cuối cùng trong một khối try-catch:

catch (<exception type1>) {…}

catch (<exception type2>) {…}

catch (<exception typeN>) {…}

catch (...) {…};

2.7. Lớp Exception trong C++:

Để tích hợp hơn nữa các ngoại lệ vào ngôn ngữ C++, lớp exception đã được

đưa vào thư viện chuẩn.

Sử dụng thư viện này, ta có thể ném các thể hiện của exception hoặc tạo các

lớp dẫn xuất từ đó.

Lớp exception có một hàm ảo what(), có thể định nghĩa lại what() để trả về

một xâu ký tự:

try {…}

catch (exception e) {

cout << e.what();

}

Page 19: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

19

Một số lớp ngoại lệ chuẩn khác được dẫn xuất từ lớp cơ sở exception. File

header <stdexcept> (cũng thuộc thư viện chuẩn C++) chứa một số lớp ngoại

lệ dẫn xuất từ exception:

File này cũng đã #include <exception> nên khi dùng không cần

#include cả hai,

Trong đó có hai lớp quan trọng được dẫn xuất trực tiếp từ exception:

runtime_error & logic_error.

runtime_error:

Dùng để đại diện cho các lỗi trong thời gian chạy (các lỗi là kết quả

của các tình huống không mong đợi, chẳng hạn: hết bộ nhớ),

Gồm các lớp lớp dẫn xuất sau:

range_error: điều kiện sau (post-condition) bị vi phạm,

overflow_error: xảy ra tràn số học,

bad_alloc: không thể cấp phát bộ nhớ.

logic_error:

Dùng cho các lỗi trong lôgic chương trình (chẳng hạn truyền tham

số không hợp lệ),

Gồm các lớp lớp dẫn xuất sau:

domain_error: điều kiện trước (pre-condition) bị vi phạm,

invalid_argument: tham số không hợp lệ được truyền cho

hàm,

length_error: tạo đối tượng lớn hơn độ dài cho phép,

out_of_range: tham số ngoài khoảng (chẳng hạn chỉ số

không hợp lệ).

Ví dụ: Viết lại hàm MyDivide() để sử dụng các ngoại lệ chuẩn:

double MyDivide(double numerator, double denominator) {

if (denominator == 0.0) {

throw invalid_argument("Loi! Mau so khong the bang 0");

exit(0);

} else {

return numerator / denominator;

}

}

Sửa lệnh catch cũ để bắt được ngoại lệ kiểu invalid_argument (thay cho kiểu

string trong phiên bản trước):

void main() {

int x, y;

double result;

do {

cout << "Nhap 2 so:";

cin >> x >> y;

try {

Page 20: Cơ chế bắt lỗi trong Java và C++

BÁO CÁO CƠ CHẾ BẮT LỖI TRONG JAVA VÀ C++

20

result = MyDivide(x, y);

}

catch (invalid_argument &e) {

cout << e.what() << endl;

continue; //Restart the loop

};

} while (0);

cout << "Ket qua chia so thu nhat cho thu hai: ";

cout<< result << "\n";

}