1.C++中的異常
C++異常處理語法元素try-catch語句
- try語句處理正常代碼邏輯 (但有可能產生異常,產生異常時拋出異常並轉到catch語句塊里面的代碼)
- catch語句處理異常情況
- try語句中的異常由對應的catch語句處理
- C++通過throw語句拋出異常信息(一般在try語句中)
throw和return區別
throw異常的返回一個值,這個值就代表了異常,
拋到catch語句塊
return正常的返回一個值
C++
異常處理分析
(1)throw拋出的異常必須被catch處理
- 當前函數能夠處理異常(含有catch語句塊),程序繼續往下執行
- 當前函數無法處理異常,則函數停止執行,並返回,由上層函數進行處理了。
(2)未被處理的異常會順着函數調用棧向上傳播,直到被處理為止,否則程序將停止執行。如果一直未處理則會到main函數,該函數中若果仍沒有try..catch語句直接退出
(3)同一個try語句可以跟上多個catch語句
①catch語句可以定義具體處理的異常類型
②不同類型的異常由不同的catch語句負責處理。
③try語句中可以拋出任何類型的異常
④catch(…)用於處理所有類型的異常
⑤任何異常都只能被捕獲(catch)一次。
(4)異常處理的匹配規則

1 #include <iostream> 2 3 using namespace std; 4 5 double divide(double a, double b) 6 { 7 const double delta = 0.000000000000001; 8 double ret = 0; 9 10 if( !((-delta < b) && ( b < delta))){ 11 ret = a / b; 12 }else{ 13 throw 0; //產生除0異常 14 } 15 16 return ret; 17 } 18 19 //匹配規則(自上而下,嚴格匹配、不進行類型轉換) 20 void Demo1() 21 { 22 try{ 23 throw 'c'; //拋出字符型的異常 24 }catch(int i){ 25 cout << "catch(int i)" << endl; 26 }catch(double d){ 27 cout << "catch(double d)" << endl; 28 }catch(char c){ //只能被這里的catch捕獲 29 cout << "catch(char c)" << endl; 30 } 31 } 32 33 void Demo2() 34 { 35 throw "Demo2"; //const char* 36 } 37 int main() 38 { 39 cout << "main() begin" << endl; 40 41 try{ 42 double c = divide(1, 0);//產生異常 43 cout <<"c = " << c << endl; //無法被執行到! 44 }catch(...){ 45 cout << "Divide by zero..." << endl; 46 } 47 48 Demo1(); 49 50 try{ 51 Demo2(); 52 } 53 catch(char* c) 54 { 55 cout << "catch(char* c)" << endl; 56 } 57 catch(const char* c) 58 { 59 cout << "catch(const char* c)" << endl; 60 }catch(...) 61 { 62 //寫位置最后 63 cout << "catch(...)" << endl; 64 } 65 66 cout << "main() end" << endl; 67 return 0; 68 }
2.異常類的構建
- 異常的類型可以是自定義的類類型
- 對於類類型異常的匹配依舊是至上而下嚴格匹配(不能強制類型的轉換)
- 賦值兼容性原則(子類的對象可以直接復制給父類的對象,父類的指針可以直接指向子類的對象)在異常匹配中依然使用 (出現父類對象是可以用一個子類對象代替)
- 一般而言:
------匹配子類異常的catch放在上部
------匹配父類異常的catch放在下部
3、異常類族
現代C++庫必然包含充要的異常類族
異常類族是數據結構類所以來的“基礎設施”

頂層父類Exception是一個抽象類,不能定義對象,用於被繼承的。
這一節就是實現這個抽象基類的。
目的:當程序拋出異常時(有可能會是一個字符串、文件名、行號),能夠捕捉到這個異常,並打印處異常的信息等。
要實現的幾個函數:
構造函數:對收到的異常進行初始化工作
1 Exception(const char* message); 2 Exception(const char* file,int line); 3 Exception(const char* message,const char* file,int line);
由於初始化工作差不多,為了代碼整潔我們將相同的操作封裝成了一個函數即:
void init(const char*,const char*,int);//由於三個構造函數中的邏輯很相似,所以可以將相似的部分統一放到一個函數init()
此外還需要保存一些初始化變量的成員變量
1 char* m_message;//m_message指向一個字符串,用於說明當前的異常信息 2 char* m_location;//m_location指向一個字符串,用於說明當前的異常位置
由於涉及到堆空間即需進行深拷貝,就不能使用默認的拷貝構造函數和賦值操作符,需要自己定義實現即
1 //涉及到堆空間即需進行深拷貝,拷貝構造函數和"=" 2 Exception(const Exception& e); 3 Exception& operator =(const Exception& e);
完整代碼如下
Exception.h
1 #ifndef _EXCEPTION_H_ 2 #define _EXCEPTION_H_ 3 namespace DataStructureLib 4 { 5 6 class Exception 7 { 8 protected: 9 char* m_message; 10 char* m_location; 11 protected: 12 void init(const char*,const char*,int);//由於三個構造函數中的邏輯很相似,所以可以將相似的部分統一放到一個函數init() 13 public: 14 Exception(const char* message); 15 Exception(const char* file,int line); 16 Exception(const char* message,const char* file,int line); 17 18 //涉及到堆空間即需進行深拷貝,拷貝構造函數和"=" 19 Exception(const Exception& e); 20 Exception& operator =(const Exception& e); 21 22 virtual const char* message() const; 23 virtual const char* location() const; 24 25 virtual ~Exception(void); 26 }; 27 #endif 28 }
Exception.cpp
1 #include "Exception.h" 2 #include <cstring> 3 #include <cstdlib> 4 5 namespace DataStructureLib 6 { 7 void Exception::init(const char* message,const char* file,int line) 8 { 9 m_message=strdup(message);//這里不能直接使用m_message=message, 10 //因為message指針指向的數據有可能會在棧、堆、全局區,如果是在棧上,局部變量可能會消失,如果直接使用m_message=message就會不安全 11 if(file!=NULL) 12 { 13 char sl[16]={0}; 14 itoa(line,sl,10);//將line轉為char類型 10代表十進制 15 16 m_location=static_cast<char* >(malloc(strlen(file)+strlen(sl)+2));//加2表示后面的":"和結束符即“/0” 17 m_location=strcpy(m_location,file); 18 m_location=strcat(m_location,":"); 19 m_location=strcat(m_location,sl); 20 } 21 } 22 23 Exception:: Exception(const char* message) 24 { 25 init(message,NULL,0); 26 } 27 28 Exception::Exception(const char* file,int line) 29 { 30 init(NULL,file,line); 31 } 32 33 Exception::Exception(const char* message,const char* file,int line) 34 { 35 init(message,file,line); 36 } 37 38 Exception::~Exception(void) 39 { 40 41 free(m_message); 42 free(m_location); 43 } 44 45 const char* Exception::message() const 46 { 47 return m_message; 48 } 49 50 const char* Exception::location() const 51 { 52 return m_location; 53 } 54 55 Exception::Exception(const Exception& e) 56 { 57 m_message=strdup(e.m_message); 58 m_location=strdup(e.m_location); 59 } 60 61 Exception& Exception::operator =(const Exception& e) 62 { 63 if (this!=&e) 64 { 65 free(m_message); 66 free(m_location); 67 68 m_message=strdup(e.m_message); 69 m_location=strdup(e.m_location); 70 } 71 return *this; 72 } 73 74 }
測試:
#include<iostream> #include "SmartPointer.h" #include "Exception.h" using namespace std; using namespace DataStructureLib; int main(int argc,char* argv[]) { try { throw(Exception("test",__FILE__,__LINE__)); } catch (const Exception& e) { cout<<e.message()<<endl; cout<<e.location()<<endl; } return 0; }
結果: