異常的概念:ios
異常(Exception)與 Bug 的對比:數組
異常處理的方式:
C語言經典處理方式:if ... else ...
ide
示例——除法操做異常處理:函數
#include <iostream> using namespace std; double divide(double a, double b, int* valid) { const double delta = 0.000000000000001; double ret = 0; if( !((-delta < b) && (b < delta)) ) { ret = a / b; *valid = 1; } else { *valid = 0; } return ret; } int main(int argc, char *argv[]) { int valid = 0; double r = divide(1, 0, &valid); if( valid ) { cout << "r = " << r << endl; } else { cout << "Divided by zero..." << endl; } return 0; }
運行結果爲:優化
[root@bogon Desktop]# g++ test.cpp [root@bogon Desktop]# ./a.out Divided by zero...
缺陷:this
經過 setjmp() 和 longjmp() 進行優化:spa
int setjmp(jmp_buf env)
void longjmp(jmp_buf env, int val)
示例——除法操做異常處理優化:指針
#include <iostream> #include <csetjmp> using namespace std; static jmp_buf env; double divide(double a, double b) { const double delta = 0.000000000000001; double ret = 0; if( !((-delta < b) && (b < delta)) ) { ret = a / b; } else { longjmp(env, 1); } return ret; } int main(int argc, char *argv[]) { if( setjmp(env) == 0 ) { double r = divide(1, 0); cout << "r = " << r << endl; } else { cout << "Divided by zero..." << endl; } return 0; }
運行結果爲:code
[root@bogon Desktop]# g++ test.cpp [root@bogon Desktop]# ./a.out Divided by zero...
setjmp() 和 longjmp() 的引入:對象
C語言中的經典異常處理方式會使得程序中邏輯中混入大量的處理異常的代碼。
正常邏輯代碼和異常處理代碼混合在一塊兒,致使代碼迅速膨脹,難以維護。。。
示例——異常處理代碼分析:
#include <iostream> using namespace std; #define SUCCESS 0 #define INVALID_POINTER -1 #define INVALID_LENGTH -2 #define INVALID_PARAMETER -3 int MemSet(void* dest, unsigned int length, unsigned char v) { if( dest == NULL ) { return INVALID_POINTER; } if( length < 4 ) { return INVALID_LENGTH; } if( (v < 0) || (v > 9) ) { return INVALID_PARAMETER; } unsigned char* p = (unsigned char*)dest; for(int i=0; i<length; i++) { p[i] = v; } return SUCCESS; } int main(int argc, char *argv[]) { int ai[5]; int ret = MemSet(ai, sizeof(ai), 0); if( ret == SUCCESS ) { } else if( ret == INVALID_POINTER ) { } else if( ret == INVALID_LENGTH ) { } else if( ret == INVALID_PARAMETER ) { } return ret; }
C++內置了異常處理的語法元素try ... catch ...:
C++經過throw語句拋出異常信息:
throw拋出的異常必須被catch處理:
未被處理的異常會順着函數調用棧向上傳播,直到被處理爲止,不然程序將中止執行。
示例——C++異常處理:
#include <iostream> using namespace std; double divide(double a, double b) { const double delta = 0.000000000000001; double ret = 0; if( !((-delta < b) && (b < delta)) ) { ret = a / b; } else { throw 0; } return ret; } int main(int argc, char *argv[]) { try { double r = divide(1, 0); cout << "r = " << r << endl; } catch(...) { cout << "Divided by zero..." << endl; } return 0; }
運行結果爲:
[root@bogon Desktop]# g++ test.cpp [root@bogon Desktop]# ./a.out Divided by zero...
同一個try語句能夠跟上多個catch語句:
異常處理的匹配規則:
示例——異常類型匹配:
#include <iostream> using namespace std; void Demo1() { try { throw 'c'; } catch(char c) { cout << "catch(char c)" << endl; } catch(short c) { cout << "catch(short c)" << endl; } catch(double c) { cout << "catch(double c)" << endl; } catch(...) { cout << "catch(...)" << endl; } } void Demo2() { throw string("HelloWorld!"); } int main(int argc, char *argv[]) { Demo1(); try { Demo2(); } catch(char* s) { cout << "catch(char *s)" << endl; } catch(const char* cs) { cout << "catch(const char *cs)" << endl; } catch(string ss) { cout << "catch(string ss)" << endl; } return 0; }
運行結果爲:
[root@bogon Desktop]# g++ test.cpp [root@bogon Desktop]# ./a.out catch(char c) catch(string ss)
catch語句塊中能夠拋出異常:
爲何要在catch中從新拋出異常?
示例——在catch中從新拋出異常:
#include <iostream> using namespace std; void Demo() { try { try { throw 'c'; } catch(int i) { cout << "Inner: catch(int i)" << endl; throw i; } catch(...) { cout << "Inner: catch(...)" << endl; throw; } } catch(...) { cout << "Outer: catch(...)" << endl; } } int main(int argc, char *argv[]) { Demo(); return 0; }
運行結果爲:
[root@bogon Desktop]# g++ test.cpp [root@bogon Desktop]# ./a.out Inner: catch(...) Outer: catch(...)
示例——異常的從新解釋:
#include <iostream> using namespace std; /* 假設: 當前的函數式第三方庫中的函數,所以,咱們沒法修改源代碼 函數名: void func(int i) 拋出異常的類型: int -1 ==》 參數異常 -2 ==》 運行異常 -3 ==》 超時異常 */ void func(int i) { if( i < 0 ) { throw -1; } if( i > 100 ) { throw -2; } if( i == 11 ) { throw -3; } cout << "Run func..." << endl; } void MyFunc(int i) { try { func(i); } catch(int i) { switch(i) { case -1: throw "Invalid Parameter"; break; case -2: throw "Runtime Exception"; break; case -3: throw "Timeout Exception"; break; } } } int main(int argc, char *argv[]) { try { MyFunc(11); } catch(const char* cs) { cout << "Exception Info: " << cs << endl; } return 0; }
運行結果爲:
[root@bogon Desktop]# g++ test.cpp [root@bogon Desktop]# ./a.out Exception Info: Timeout Exception
C++中的異常處理:
(根據賦值兼容性原則:子類的異常對象能夠被父類的catch語句塊抓住。)
C++中的異常處理:
示例——類類型的異常:
#include <iostream> using namespace std; class Base { }; class Exception : public Base { int m_id; string m_desc; public: Exception(int id, string desc) { m_id = id; m_desc = desc; } int id() const { return m_id; } string description() const { return m_desc; } }; /* 假設: 當前的函數式第三方庫中的函數,所以,咱們沒法修改源代碼 函數名: void func(int i) 拋出異常的類型: int -1 ==》 參數異常 -2 ==》 運行異常 -3 ==》 超時異常 */ void func(int i) { if( i < 0 ) { throw -1; } if( i > 100 ) { throw -2; } if( i == 11 ) { throw -3; } cout << "Run func..." << endl; } void MyFunc(int i) { try { func(i); } catch(int i) { switch(i) { case -1: throw Exception(-1, "Invalid Parameter"); break; case -2: throw Exception(-2, "Runtime Exception"); break; case -3: throw Exception(-3, "Timeout Exception"); break; } } } int main(int argc, char *argv[]) { try { MyFunc(11); } catch(const Exception& e) { cout << "Exception Info: " << endl; cout << " ID: " << e.id() << endl; cout << " Description: " << e.description() << endl; } catch(const Base& e) { cout << "catch(const Base& e)" << endl; } return 0; }
運行結果爲:
[root@bogon Desktop]# g++ test.cpp [root@bogon Desktop]# ./a.out Exception Info: ID: -3 Description: Timeout Exception
C++中的異常處理:
標準庫中的異常:
示例——標準庫中的異常使用(優化以前的Array.h和HeapArray.h):
// Array.h #ifndef _ARRAY_H_ #define _ARRAY_H_ #include <stdexcept> using namespace std; template < typename T, int N > class Array { T m_array[N]; public: int length() const; bool set(int index, T value); bool get(int index, T& value); T& operator[] (int index); T operator[] (int index) const; virtual ~Array(); }; template < typename T, int N > int Array<T, N>::length() const { return N; } template < typename T, int N > bool Array<T, N>::set(int index, T value) { bool ret = (0 <= index) && (index < N); if( ret ) { m_array[index] = value; } return ret; } template < typename T, int N > bool Array<T, N>::get(int index, T& value) { bool ret = (0 <= index) && (index < N); if( ret ) { value = m_array[index]; } return ret; } template < typename T, int N > T& Array<T, N>::operator[] (int index) { if( (0 <= index) && (index < N) ) { return m_array[index]; } else { throw out_of_range("T& Array<T, N>::operator[] (int index)"); } } template < typename T, int N > T Array<T, N>::operator[] (int index) const { if( (0 <= index) && (index < N) ) { return m_array[index]; } else { throw out_of_range("T Array<T, N>::operator[] (int index) const"); } } template < typename T, int N > Array<T, N>::~Array() { } #endif
// HeapArray.h #ifndef _HEAPARRAY_H_ #define _HEAPARRAY_H_ #include <stdexcept> using namespace std; template < typename T > class HeapArray { private: int m_length; T* m_pointer; HeapArray(int len); HeapArray(const HeapArray<T>& obj); bool construct(); public: static HeapArray<T>* NewInstance(int length); int length() const; bool get(int index, T& value); bool set(int index ,T value); T& operator [] (int index); T operator [] (int index) const; HeapArray<T>& self(); const HeapArray<T>& self() const; ~HeapArray(); }; template < typename T > HeapArray<T>::HeapArray(int len) { m_length = len; } template < typename T > bool HeapArray<T>::construct() { m_pointer = new T[m_length]; return m_pointer != NULL; } template < typename T > HeapArray<T>* HeapArray<T>::NewInstance(int length) { HeapArray<T>* ret = new HeapArray<T>(length); if( !(ret && ret->construct()) ) { delete ret; ret = 0; } return ret; } template < typename T > int HeapArray<T>::length() const { return m_length; } template < typename T > bool HeapArray<T>::get(int index, T& value) { bool ret = (0 <= index) && (index < length()); if( ret ) { value = m_pointer[index]; } return ret; } template < typename T > bool HeapArray<T>::set(int index, T value) { bool ret = (0 <= index) && (index < length()); if( ret ) { m_pointer[index] = value; } return ret; } template < typename T > T& HeapArray<T>::operator [] (int index) { if( (0 <= index) && (index < length()) ) { return m_pointer[index]; } else { throw out_of_range("T& HeapArray<T>::operator [] (int index)"); } } template < typename T > T HeapArray<T>::operator [] (int index) const { if( (0 <= index) && (index < length()) ) { return m_pointer[index]; } else { throw out_of_range("T HeapArray<T>::operator [] (int index) const"); } } template < typename T > HeapArray<T>& HeapArray<T>::self() { return *this; } template < typename T > const HeapArray<T>& HeapArray<T>::self() const { return *this; } template < typename T > HeapArray<T>::~HeapArray() { delete[]m_pointer; } #endif
// test.cpp #include <iostream> #include "Array.h" #include "HeapArray.h" using namespace std; void TestArray() { Array<int, 5> a; for(int i=0; i<a.length(); i++) { a[i] = i; } for(int i=0; i<a.length(); i++) { cout << a[i] << endl; } } void TestHeapArray() { HeapArray<double>* pa = HeapArray<double>::NewInstance(5); if( pa != NULL ) { HeapArray<double>& array = pa->self(); for(int i=0; i<array.length(); i++) { array[i] = i; } for(int i=0; i<array.length(); i++) { cout << array[i] << endl; } } delete pa; } int main(int argc, char *argv[]) { try { TestArray(); cout << endl; TestHeapArray(); } catch(...) { cout << "Exception" << endl; } return 0; }
運行結果爲:
[root@bogon Desktop]# g++ test.cpp [root@bogon Desktop]# ./a.out 0 1 2 3 4 0 1 2 3 4