目錄
- 異常匹配
- catch: 按異常類型匹配
- 為何要使用異常類
- 內建異常類
- 標準庫中的異常基類
- 標準庫中的異常類
- 例1:vector下標訪問越界out_of_range異常
- 例2:內存分配失敗bad_alloc異常
- 例3:側向轉換失敗bad_cast異常類
- 幾種情況,使用對應異常
異常匹配
catch: 按異常類型匹配
已知try是監視可能出現問題的代碼,throw是扔出問題,catch是看扔出的問題是否和它的類型匹配,如果是匹配那么就抓住問題進行處理。
這里的類型使用傳引用,避免拷貝浪費。
catch ( ExceptionType& parameter ) { /* 處理異常 */ }
若try{}中所拋異常類型與catch()的參數類型(ExceptionType)匹配,則進入catch塊
若對異常對象的內容不感興趣,可省略catch參數,只保留類型。
如:
catch ( ExceptionType& ) { /* 處理異常 */ }
舉例:
f1()拋出整型異常。
f2()是要申請28G內存,如果電腦內存不夠,執行代碼會出錯,拋出bad_alloc異常。這是C++規定的,new出現問題就會拋出bad_alloc異常。bad_alloc是C++異常類exception基類的派生類。
void f1() { throw 100; }
void f2() { for (int i = 1; i <= 100; i++) new int[70000000]; }
對于f1的兩種處理:
try { f1(); }
catch (int) { //僅有類型cout << "Error" << endl;
}try { f1(); }
catch (int& e) { //類型+參數cout << e << endl;
}
對于f2的兩種處理:
注意e.what()是exception類內部的一個虛函數,返回的是一個指針,指向一個字符串,包含了異常的解釋信息。
try { f2(); }
catch (bad_alloc) {cout << "new failed" << endl;
}
try { f2(); }
catch (bad_alloc &e) {cout << "Exception: " << e.what() << endl;
}
為何要使用異常類
整數作為異常類型,只能獲取整數的信息。
不使用異常類,則捕獲的異常所能傳遞的信息量很少。
try {// ...
}
catch (int e) {//do something with e
}
使用異常類,則可以在拋出異常時傳遞很多信息,在捕獲異常時接收這些信息。
class Beautiful {string name;string hometown;int salary;string misdoing;
// …………
}
try {// ...
}
catch (Beautiful object) {//do something with object
}
內建異常類
標準庫中的異常基類
exception 是標準庫所有異常類的基類
使用異常類需要包括頭文件 #include <exception>
class exception需要注意的部分如下:
exception(); // 構造函數
virtual const char* what(); //返回解釋性字符串
what()返回的指針指向擁有解釋信息的空終止字符串的指針。該指針保證在獲取它的異常對象被銷毀前,或在調用該異常對象的非靜態成員函數前合法
標準庫中的異常類
在使用所有標準庫異常類的時候,都必須附加std名字空間。
runtime_error與logic_error的使用區別
來自wiki的解釋:
邏輯錯誤:(有時稱為語義錯誤)是程序中的一個錯誤,它會導致程序錯誤運行,但不會異常終止(或崩潰)。邏輯錯誤會產生非預期或不希望的輸出或其他行為,盡管它可能不會立即被識別。
編譯語言和解釋語言都會出現邏輯錯誤。與有語法錯誤的程序不同,有邏輯錯誤的程序在語言中是有效的程序,盡管它的行為不符合預期。
運行時錯誤:一個錯誤在程序執行過程中發生的。相反,編譯時錯誤發生在程序編譯時。運行時錯誤表示程序中的錯誤或設計人員預期的問題,但卻無能為力。例如,內存不足通常會導致運行時錯誤。
例1:vector下標訪問越界out_of_range異常
vector有許多種訪問元素的方式,其中[]下標訪問不會做越界檢查,at()會做越界檢查。
我們將它截獲
例2:內存分配失敗bad_alloc異常
#include<iostream>
using namespace std;
int main()
{for( int i = 0; i < 10000; i++){auto *p = new long long int [70000];cout << i << "array" << endl;}return 0;
}
進行捕獲
#include<iostream>
#include <exception>
#include <stdexcept>
#include <new>
using namespace std;
int main()
{try {for (int i = 0; i < 10000; i++){auto* p = new long long int[70000];cout << i << "array" << endl;}}catch (bad_alloc& e){cout << "exception " << e.what() << endl;}return 0;
}
程序正常退出。
例3:側向轉換失敗bad_cast異常類
創建基類student
創建派生類Undergraduate和Graduate
主函數中用dynamic_cast 將Undergraduate類型轉換為Graduate類型.
dynamic_cast只有在做引用類型轉換時候轉換失敗才會拋出異常。使用指針類型時,如果轉換失敗會返回nullptr
#include <iostream>
#include <exception>
#include <stdexcept>using namespace std;class Student {
public:Student() = default;virtual void foo() {};
};
class Undergraduate : public Student {};
class Graduate : public Student {};
int main()
{Undergraduate u;Graduate g;Student *s1 = &u;Student *s2 = &g;//正常操作,p指針不為nullptrGraduate *p = dynamic_cast<Graduate *>(s2);//轉化不成功,p2指針為nullptrGraduate *p2 = dynamic_cast<Graduate *>(s1);if(p2 == nullptr){cout << "cast s1 to Graduate* failed " << endl;}else{cout << "cast s1 to Graduate* succeeded " << endl;}//引用,拋異常try{Graduate &r1 = dynamic_cast<Graduate &> (u);}catch (bad_cast & e){cout << "Exception: " << e.what() << endl;}return 0;
}
幾種情況,使用對應異常
1、除法運算中除數為0;
:invalid_argument2、在只讀文件系統中以寫模式打開一個文件流;
:filesystem::filesystem_error
3、 數組a的容量為5,向 a[5] 中寫入數據;
:out_of_range4、用 new 申請內存失敗;
:bad_array_new_length
5、將A指針類型轉換為B指針類型失敗;
:bad_any_cast
6、將 1234567 這個整數存到一個 short int 類型的變量中(在32位C++編譯器中編譯)
:length_error