1 異常常識:
1)使用throw拋出異常;
2)使用try-catch 語句塊捕獲異常;
3)catch語句塊中,可以使用throw再次拋出當前異常
try {
g();
} catch (int i) {
throw;//再次拋出異常
}
4)可以拋出任意類型的異常魄眉≡尤常可以是對象杰赛,也可以是簡單的基礎類型。
void process() {
if (fail) {
throw 5;
}
}
try {
process():
} catch (int e) {
return 1;
}
5)也可以拋出C風格的字符串char*
void process() {
if (fail) {
throw "failed exception"
}
}
try {
process():
} catch (const char* e) {
std:cerr << e << endl;
}
6)通常應該拋出對象。因為對象的類名稱可以傳遞信息抖单;此外異常可以存儲信息遇八,包括用于描述異常的字符串矛绘;
7) 以下為匹配所有異常的代碼:
try {
} catch (...) {
}
try {
} catch (const invalid_argument& e) {
} catch (const runtime_error& e) {
} catch (...) {
}
8)如果程序拋出的異常沒有被捕獲,程序將終止刃永』醢可以對main()函數(shù)使用try-catch結構以捕獲所有沒有被捕獲的異常;
2 拋出列表
C++允許指定函數(shù)或者方法可以拋出的異常斯够。也即拋出列表囚玫。
void readFile()
throw(invalid_argument, runtime_error)
{
//code
}
注意:
1)不能僅僅根據(jù)拋出列表中的不同異常重載函數(shù)喧锦;
2)如果函數(shù)/方法沒有指定拋出列表,那么可以拋出任意異常抓督。
3)如果不想讓函數(shù)/方法拋出異常燃少,可以使用noexcept
void readFile() noexcept;
4)函數(shù)/方法可以拋出 拋出列表之外的異常,但是會導致程序終止铃在;
void readFile() throw(invalid_argument, runtime_error) {
throw 5;
}
int main() {
try {
readFile();
} catch (int x) {
}
return 0;
}
上面的代碼會導致程序終止阵具。
5)set_unexcepted
如果出現(xiàn)意料之外的異常,可以使用set_unexcepted更改其行為涌穆。
規(guī)則如下:
(1)如果處理函數(shù)拋出一個新的異常怔昨,這個新的異常將會替換掉意料之外的異常,就像新的異常是最初被拋出的一樣宿稀。
(2)如果新拋出的異常也不在拋出列表中趁舀,程序處理如下:
(2.1)如果拋出列表給出了bad_exception,就拋出bad_exception祝沸;
(2.2)如果拋出列表沒有給出bac_exception矮烹,就終止;
set_unexcepted通常用于將意料之外的異常轉化為預期的異常罩锐;
void myUnexcepted() {
throw runtime_error("");
}
int main() {
unexcepted_handler old_handler = set_unexcepted(myUnexcepted);//保存舊的處理函數(shù)
try {
} catch (int e) {
} catch (const runtime_error& e) {
}
set_unexcepted(old_handler);//還原
}
由于unexcepted函數(shù)作用于整個引用程序而不是這個函數(shù)奉狈,所以當需要特殊處理程序的代碼結束以后,需要還原處理程序涩惑。
3 在重寫方法中修改拋出列表
在子類中重寫虛方法時仁期,如果想讓拋出列表比父類中的拋出列表更加嚴格,可以修改拋出列表竭恬。
總結為允許三種情況:
1)刪除列表中的異常(注意不是全部刪除)跛蛋;
2)添加超類拋出列表中異常的子類;
3)將方法設置為noexcept痊硕;
代碼例子:
class D {
};
class A {
};
class B : public A {
};
class C : public B {
};
class Foo {
public:
void virtual func() throw (A,D) = 0;
};
class Bar: public Foo {
public:
void virtual func() throw(A);//刪除異常D赊级,允許
void virtual func() throw(A,D,B);//添加A的子類,允許
void virtual func() throw(B,C);//允許
//void virtual func() noexcept;//允許
//void virtual func() throw(B, int);//不允許
//void virtual func();//全部刪除岔绸,不允許
};
4 嵌套異常
using namespace std;
class MyException : public exception {
public:
MyException(const char* msg):mMsg("") {
mMsg = msg;
}
virtual ~MyException() noexcept {}
virtual const char* what() const noexcept override {
return mMsg.c_str();
}
private:
string mMsg;
};
void doSomething() {
try {
throw runtime_error("runtime_error");
} catch (const runtime_error& e) {
cout << "catch runtime_error exception : " << e.what() << endl;
cout <<" throw MyException :" << endl;
throw_with_nested(MyException("Myxception"));
}
}
int main(int argc, const char * argv[]) {
// insert code here...
try {
doSomething();
} catch (const MyException& e) {
const nested_exception *p = dynamic_cast<const nested_exception*>(&e);
if (p) {
try {
p->rethrow_nested();
} catch (const runtime_error& e) {
cout << "nested exceprion => " << e.what() << endl;
}
}
}
}
執(zhí)行結果:
catch runtime_error exception : runtime_error
throw MyException :
nested exceprion => runtime_error
備注:
1)C++高級編程中理逊,講到嵌套類必須要同時繼承混入類std::nested_exception,但是實際測試盒揉,不繼承也是可以的晋被。
2) 上面使用dynamic_cast將MyException轉型,然后獲取嵌套類刚盈,可以使用rethrow_if_nested簡化墨微,代碼如下:
int main(int argc, const char * argv[]) {
// insert code here...
try {
doSomething();
} catch (const MyException& e) {
try {
std::rethrow_if_nested(e);
} catch (const runtime_error& e1) {
cout << "nested exceprion => " << e1.what() << endl;
}
}
}