C++中的捕獲異常機制catch參數中實參的類型不同,采取的處理方式則不相同,且與普通的函數調用還不一樣,具體表現為當拋出異常throw A()或throw obj時,對象會進行一次額外的對象復制操作。
測試類實現如下:
#include <iostream> /** * 測試異常拋出與虛函數 */ using namespace std; class A { public: A() {cout << "A() " << endl;} ~A(){cout << "~A()" << endl;} A(const A& a){cout << "A(a)" << endl;} virtual void func(){cout << "A::func()" << endl;} }; class B:public A { B() {cout << "B()" << endl;} B(const B &b) {cout << "B(b)" << endl;} ~B(){cout << "~B()" << endl;} virtual void func() {cout << "B::func()" << endl;} };
1) 當采用對象傳遞方式捕獲異常時,在對象中會發生兩次復制操作,一次為對象a復制給臨時對象,二次為臨時對象通過引用方式傳遞給實參b。
void f1(const A &a) { try { cout << "------ function f1: --------" << endl; throw a; } catch( A b) { cout << "exception A b" << endl; } cout << "---- function f1 -------" << endl; }
該段代碼執行結果如下:
------ function f1: --------
A(a)
A(a)
exception A b
~A()
~A()
---- function f1 -------
2) 當采用引用方式捕獲異常時,就會少了上面第二次的復制開銷,即生成臨時對象直接作為參數傳遞。
void f2(const A &a) { try { cout << "------ function f2: --------" << endl; throw a; } catch( const A &b) { cout << "exception A &b" << endl; } cout << "---- function f2 -------" << endl; }
執行結果如下:
------ function f2: -------- A(a) exception A &b ~A() ---- function f2 -------
3) 如果直接拋出引用對象,系統會報錯,因為異常處理機制不局限於當前函數,有可能在該函數之外。
void f3(const A &a) { try { cout << "------ function f3: --------" << endl; throw &a;//引用異常,系統會意外終止 } catch(const A &b) { cout << "exception A &b" << endl; } cout << "---- function f3 -------" << endl; }
4) 拋出異常時,可直接拋出對象,也可生成一個對象,不同的是這樣會顯式調用構造函數非復制構造函數。
void f4(const A &a) { try { cout << "------ function f4: --------" << endl; throw A(); } catch(const A &b) { cout << "exception A &b" << endl; } cout << "---- function f4 -------" << endl; }
執行結果如下:
------ function f4: -------- A() exception A &b ~A() ---- function f4 -------
5) 在處理帶有繼承的異常類時,異常處理規則不是按照虛函數繼承中”最優匹配(best fit)”原則,而是”最先匹配(first fit)”原則進行處理。
void f5(const B& b) { try { cout << "------ function f5: --------" << endl; throw b; } catch(const A &a) { cout << "exception A &a" << endl; } catch(const B &b1) { cout << "exception B &b1" << endl; } cout << "---- function f5 -------" << endl; }
該異常會匹配A而非B:
------ function f5: -------- A() B(b) exception A &a ~B() ~A() ---- function f5 -------