【转】【C++学习笔记】C++异常处理
轉自:【C++學習筆記】C++異常處理!你絕對不能錯過的干貨! - 知乎
合理地使用C++異常處理,能夠使我們寫出來的程序更加穩定強健,不易崩潰。那么,應該如何使用C++異常處理呢?下面,我們就來向大家介紹最簡單也是最常用的異常處理語句 。
一、什么是異常
用官方的話來說就是程序在執行過程中產生的問題,換句通俗的話來講就是程序執行的出現的異常,比如程序崩了、內存泄漏了、數組越界以及其他異常信息的出現。
異常提供了一種轉移程序控制權的方式。C++ 異常處理涉及到三個關鍵字:try、catch、throw。
throw:?當問題出現時,程序會拋出一個異常。這是通過使用?throw?關鍵字來完成的。
catch:?在您想要處理問題的地方,通過異常處理程序捕獲異常。catch?關鍵字用于捕獲異常。
try:?try?塊中存放可能出現異常的代碼。它后面通常跟著一個或多個 catch 塊。
如果有一個塊拋出一個異常,捕獲異常的方法會使用?try?和?catch?關鍵字。try 塊中放置可能拋出異常的代碼,try 塊中的代碼被稱為保護代碼。使用 try/catch 語句的語法如下所示:
try{
// 保護代碼
}catch( ExceptionName e1 )
{
// catch 塊
}catch( ExceptionName e2 )
{
// catch 塊
}catch( ExceptionName eN )
{
// catch 塊
}
如果 try 塊在不同的情境下會拋出不同的異常,這個時候可以嘗試羅列多個 catch 語句,用于捕獲不同類型的異常。
二、拋出異常
您可以使用?throw?語句在代碼塊中的任何地方拋出異常。throw 語句的操作數可以是任意的表達式,表達式的結果的類型決定了拋出的異常的類型。
以下是嘗試除以零時拋出異常的實例:
double division(int a, int b){
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
三、捕獲異常
catch?塊跟在?try?塊后面,用于捕獲異常。您可以指定想要捕捉的異常類型,這是由 catch 關鍵字后的括號內的異常聲明決定的。
try{
// 保護代碼
}catch( ExceptionName e )
{
// 處理 ExceptionName 異常的代碼
}
上面的代碼會捕獲一個類型為?ExceptionName?的異常。如果您想讓 catch 塊能夠處理 try 塊拋出的任何類型的異常,則必須在異常聲明的括號內使用省略號?...,如下所示:
try{
// 保護代碼
}catch(...)
{
// 能處理任何異常的代碼
}
下面是一個實例,拋出一個除以零的異常,并在 catch 塊中捕獲該異常。
#include <iostream>using namespace std;
double division(int a, int b)
{
if( b == 0 )
{
throw "Division by zero condition!";
}
return (a/b);
}
int main ()
{
int x = 50;
int y = 0;
double z = 0;
try {
z = division(x, y);
cout << z << endl;
}catch (const char* msg) {
cerr << msg << endl;
}
return 0;
}
由于我們拋出了一個類型為?const char*?的異常,因此,當捕獲該異常時,我們必須在 catch 塊中使用 const char*。當上面的代碼被編譯和執行時,它會產生下列結果:
Division by zero condition!四、異常的處理規則
throw拋出的異常類型與catch抓取的異常類型要一致;
throw拋出的異常類型可以是子類對象,catch可以是父類對象;
catch塊的參數推薦采用地址傳遞而不是值傳遞,不僅可以提高效率,還可以利用對象的多態性。另外,派生類的異常捕獲要放到父類異常撲獲的前面,否則,派生類的異常無法被撲獲;
如果使用catch參數中,
使用基類捕獲派生類對象,一定要使用傳遞引用的方式,
例如catch (exception &e);
異常是通過拋出對象而引發的,該對象的類型決定了應該激活哪個處理代碼;
被選中的處理代碼是調用鏈中與該對象類型匹配且離拋出異常位置最近的那一個;
在try的語句塊內聲明的變量在外部是不可以訪問的,即使是在catch子句內也不可以訪問;
棧展開會沿著嵌套函數的調用鏈不斷查找,直到找到了已拋出的異常匹配的catch子句。如果拋出的異常一直沒有函數捕獲(catch),則會一直上傳到c++運行系統那里,導致整個程序的終止。
五、C++ 標準的異常
C++ 提供了一系列標準的異常,定義在?<exception>?中,我們可以在程序中使用這些標準的異常。它們是以父子類層次結構組織起來的,如下所示:
下表是對上面層次結構中出現的每個異常的說明:
異常描述
六、定義新的異常
您可以通過繼承和重載?exception?類來定義新的異常。下面的實例演示了如何使用?std::exception?類來實現自己的異常:
實例
#include <iostream>#include <exception>
using namespace std;
struct MyException : public exception
{
? const char * what () const throw () { return "C++ Exception";
? }
};
int main()
{
? try
? {
? ? ? ? throw MyException();
? ?}
??catch(MyException& e)
? {
? ? ? ??std::cout << "MyException caught" << std::endl;
? ? ? ? std::cout << e.what() << std::endl;
? }
? catch(std::exception& e)
? {
? ? ? ??//其他的錯誤
?? }
}
這將產生以下結果:
MyException caughtC++ Exception
在這里,what()?是異常類提供的一個公共方法,它已被所有子異常類重載。這將返回異常產生的原因。
七、總結
1. 使用異常處理的優點:
傳統錯誤處理技術,檢查到一個錯誤,只會返回退出碼或者終止程序等等,我們只知道有錯誤,但不能更清楚知道是哪種錯誤。使用異常,把錯誤和處理分開來,由庫函數拋出異常,由調用者捕獲這個異常,調用者就可以知道程序函數庫調用出現的錯誤是什么錯誤,并去處理,而是否終止程序就把握在調用者手里了。
2. 使用異常的缺點:
如果使用異常,光憑查看代碼是很難評估程序的控制流:函數返回點可能在你意料之外,這就導致了代碼管理和調試的困難。啟動異常使得生成的二進制文件體積變大,延長了編譯時間,還可能會增加地址空間的壓力。
C++沒有垃圾回收機制,資源需要自己管理。有了異常非常容易導致內存泄漏、死鎖等異常安全問題。 這個需要使用RAII來處理資源的管理問題。學習成本較高。
C++標準庫的異常體系定義得不好,導致大家各自定義各自的異常體系,非常的混亂。
3. 什么時候使用異常?
建議:除非已有的項目或底層庫中使用了異常,要不然盡量不要使用異常,雖然提供了方便,但是開銷也大。
4. 程序所有的異常都可以catch到嗎?
并非如此,只有發生異常,并且又拋出異常的情況才能被?catch?到。例如,數組下標訪問越界的情況,系統是不會自身拋出異常的,所以我們無論怎么?catch?都是無效的;在這種情況,我們需要自定義拋出類型,判斷數組下標是否越界,然后再根據自身需要throw自定義異常對象,這樣才可以catch到異常,并進行進一步處理。
看到這里你是不是對“C++”又有了一點新的認知呢~
如果你喜歡這篇文章的話,動動小指,加個關注哦~
如果你也想成為程序員,想要快速掌握編程,這里為你分享一個學習企鵝圈子
里面有資深專業軟件開發工程師,在線解答你的所有疑惑~C語言入門“so easy”
資料包含:編程入門、游戲編程、課程設計、黑客等。
總結
以上是生活随笔為你收集整理的【转】【C++学习笔记】C++异常处理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2017申请信用卡提供哪种证明好
- 下一篇: 2020年福字币预约时间,3元福字纪念币