C++語法系列之9-- 異常處理

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;
        }
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市扁掸,隨后出現(xiàn)的幾起案子翘县,更是在濱河造成了極大的恐慌,老刑警劉巖谴分,帶你破解...
    沈念sama閱讀 211,817評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锈麸,死亡現(xiàn)場離奇詭異,居然都是意外死亡牺蹄,警方通過查閱死者的電腦和手機忘伞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沙兰,“玉大人氓奈,你說我怎么就攤上這事《μ欤” “怎么了舀奶?”我有些...
    開封第一講書人閱讀 157,354評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斋射。 經常有香客問我育勺,道長,這世上最難降的妖魔是什么罗岖? 我笑而不...
    開封第一講書人閱讀 56,498評論 1 284
  • 正文 為了忘掉前任涧至,我火速辦了婚禮,結果婚禮上桑包,老公的妹妹穿的比我還像新娘南蓬。我一直安慰自己,他們只是感情好哑了,可當我...
    茶點故事閱讀 65,600評論 6 386
  • 文/花漫 我一把揭開白布赘方。 她就那樣靜靜地躺著,像睡著了一般垒手。 火紅的嫁衣襯著肌膚如雪蒜焊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評論 1 290
  • 那天科贬,我揣著相機與錄音泳梆,去河邊找鬼。 笑死榜掌,一個胖子當著我的面吹牛优妙,可吹牛的內容都是我干的。 我是一名探鬼主播憎账,決...
    沈念sama閱讀 38,979評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼套硼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了胞皱?” 一聲冷哼從身側響起邪意,我...
    開封第一講書人閱讀 37,722評論 0 266
  • 序言:老撾萬榮一對情侶失蹤九妈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后雾鬼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萌朱,經...
    沈念sama閱讀 44,189評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,519評論 2 327
  • 正文 我和宋清朗相戀三年策菜,在試婚紗的時候發(fā)現(xiàn)自己被綠了晶疼。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,654評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡又憨,死狀恐怖翠霍,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情蠢莺,我是刑警寧澤寒匙,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站浪秘,受9級特大地震影響蒋情,放射性物質發(fā)生泄漏。R本人自食惡果不足惜耸携,卻給世界環(huán)境...
    茶點故事閱讀 39,940評論 3 313
  • 文/蒙蒙 一棵癣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧夺衍,春花似錦狈谊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至矛紫,卻和暖如春赎瞎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背颊咬。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評論 1 266
  • 我被黑心中介騙來泰國打工务甥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喳篇。 一個月前我還...
    沈念sama閱讀 46,382評論 2 360
  • 正文 我出身青樓敞临,卻偏偏與公主長得像,于是被迫代替她去往敵國和親麸澜。 傳聞我的和親對象是個殘疾皇子挺尿,可洞房花燭夜當晚...
    茶點故事閱讀 43,543評論 2 349

推薦閱讀更多精彩內容