C++異常處理
1. 異常處理的使用
首先說明,千萬別對異常處理鑽牛角尖,那樣會死人的(當然是煩死的)!
在C++程式設計處理中,我秉承這樣一個思想,就是:能不用異常處理的就不用。因為造成的混亂實在是太——多了。如果能用其他方法捕捉到錯誤並處理的話,誓死不用異常處理!呵呵,或許有點偏激,但我認為,這不失為一個避免不必要的錯誤的一個好辦法。當什麼分配記憶體失敗,開啟檔案失敗之類的通常錯誤,我們只需用assert,abort之類的函式就解決問題了。也就是說,假如有足夠的資訊去處理一個錯誤,那麼這個錯誤就不是異常。
當然了,異常處理的存在也有它本身的意義和作用。不是你說不用就不用的,有些地方還非得用不可!
比如說,在當前上下文環境中,無法捕捉或確定的錯誤型別,我們就得用一個異常丟擲到更大的上下文環境當中去。還有,異常處理的使用呢,可以使出錯處理程式與“通常”程式碼分離開來,使程式碼更簡潔更靈活。另外就是程式必不可少的健壯性了,異常處理往往在其中扮演著重要的角色。
OK,下面闡述一下。
2. 丟擲異常
關——鍵字(周星馳的語氣):throw
例——句:throw ExceptionClass(“oh, shit! it’s a exception!L “);
例句中,ExceptionClass是一個類,它的建構函式以一個字串做為引數,用來說明異常。也就是說,在throw的時候,C++的編譯器先構造一個ExceptionClass的物件,讓它作為throw的返回值,拋——出去。同時,程式返回,呼叫析構。看下面這個程式:
#include <iostream.h>
class ExceptionClass{
char* name;
public:
ExceptionClass(char* name="default name") {
cout<<"Construct "<<name<<endl;
this->name=name;
}
~ExceptionClass() {
cout<<"Destruct "<<name<<endl;
}
void mythrow(){
throw ExceptionClass("o,my god");
}
};
void main(){
ExceptionClass e("haha");
try {
e.mythrow();
} catch(...) {
}
}
大家看看結果就知道了,throw後,呼叫當前類的析構,整個結束了這個類的歷史使命。唉~~
3. 異常規格說明
如果我們呼叫別人的函式,裡面有異常丟擲,我用去檢視它的原始碼去看看都有什麼異常丟擲嗎?可以,但是太——煩躁。比較好的解決辦法,是編寫帶有異常丟擲的函式時,採用異常規格說明,使我們看到函式宣告就知道有哪些異常出現。
異常規格說明大體上為以下格式:
void ExceptionFunction(argument…) throw(ExceptionClass1, ExceptionClass2, ….)
對了,所有異常類都在函式末尾的throw()的括號中得以說明了,這樣,對於函式呼叫者來說,是一清二楚了!
注意下面一種形式:
void ExceptionFunction(argument…) throw()
表明沒有任何異常丟擲。
而正常的void ExceptionFunction(argument…)則表示:可能丟擲任何一種異常,當然就,也可能沒有異常,意義是最廣泛的哦。
4. 構造和析構中的異常丟擲
55555,到了應該注意的地方了。
先看個程式,假如我在建構函式的地方丟擲異常,這個類的析構會被呼叫嗎?可如果不呼叫,那類裡的東西豈不是不能被釋放了??
程式:
#include <iostream.h>
#include <stdlib.h>
class ExceptionClass1{
char* s;
public:
ExceptionClass1(){
cout<<"ExceptionClass1()"<<endl;
s=new char[4];
cout<<"throw a exception"<<endl;
throw 18;
}
~ExceptionClass1(){
cout<<"~ExceptionClass1()"<<endl;
delete[] s;
}
};
void main(){
try{
ExceptionClass1 e;
}catch(...)
{}
}
結果為:
ExceptionClass1()
throw a exception
沒了,沒了,到此為止了!可是,可是,在這兩句輸出之間,我們已經給S分配了記憶體,哪裡去了?記憶體釋放了嗎?沒有,沒有,因為它是在解構函式中釋放的,哇!問題大了去了。怎麼辦?怎麼辦?
為了避免這種情況,應避免物件通過本身的建構函式涉及到異常丟擲。即:既不在建構函式中出現異常丟擲,也不應在建構函式呼叫的一切東西中出現異常丟擲。否則,只有完蛋。
那麼,在解構函式中的情況呢?我們已經知道,異常丟擲之後,就要呼叫本身的解構函式,如果這解構函式中還有異常丟擲的話,則已存在的異常尚未被捕獲,會導致異常捕捉不到哩。
完,也就是說,我們不要在建構函式和解構函式中存在異常丟擲。
5. 異常捕獲
上邊的程式不知道大家看懂了沒,異常捕獲已經在上面出現了也。
沒錯,就是try{…}catch(…){…}這樣的結構!
Try後面的花括號中,就是有可能涉及到異常的各種宣告啊呼叫啊之類的,如果有異常丟擲,就會被異常處理器截獲捕捉到,轉給catch處理。先把異常的類和catch後面小括號中的類進行比較,如果一致,就轉到後面的花括號中進行處理。
例如丟擲異常是這麼寫的:
void f(){throw ExceptionClass(“ya, J”);}
假設類ExceptionClass有個成員函式function()在有異常時進行處理或相應的訊息顯示(只是做個例子哦,別挑我的刺兒)。
那麼,我可以這麼捕捉: try{f()}catch(ExceptionClass e){e.function()};
當然,象在上面程式中出現的一樣,我可以在catch後用三個點來代表所有異常。如try{f()}catch(…){}。這樣就截斷了所有出現的異常。有助於把所有沒出現處理的異常遮蔽掉(我是這麼認為的J)。
異常捕獲之後,我可以再次丟擲,就用一個不帶任何引數的throw語句就可以了,例如:try(f())catch(…){throw}
6. 標準異常
正象許多人想象的一樣,C++肯定有自己的標準的異常類。
一個總基類:
exception 是所有C++異常的基類。
下面派生了兩個異常類:
logic_erro 報告程式的邏輯錯誤,可在程式執行前被檢測到。
runtime_erro 顧名思義,報告程式執行時的錯誤,只有在執行的時候才能檢測到。
以上兩個又分別有自己的派生類:
由logic_erro派生的異常類
domain_error 報告違反了前置條件
invalid_argument 指出函式的一個無效引數
length_error 指出有一個產生超過NPOS長度的物件的企圖(NPOS為size_t的最大可表現值
out_of_range 報告引數越界
bad_cast 在執行時型別識別中有一個無效的dynamic_cast表示式
bad_typeid 報告在表示式typeid(*p)中有一個空指標P
由runtime_error派生的異常
range_error 報告違反了後置條件
overflow_error 報告一個算術溢位
bad_alloc 報告一個儲存分配錯誤
相關文章
- C++異常處理機制C++
- 【C++】 C++異常捕捉和處理C++
- C++ 異常處理機制詳解:輕鬆掌握異常處理技巧C++
- C++錯誤和異常處理C++
- C++整理19_異常處理C++
- 異常篇——異常處理
- 異常處理
- 【C++】 63_C語言異常處理C++C語言
- JSP 異常處理如何處理?JS
- 異常-throws的方式處理異常
- React 異常處理React
- JS異常處理JS
- oracle異常處理Oracle
- Python——異常處理Python
- Python異常處理Python
- ThinkPHP 異常處理PHP
- JavaScript 異常處理JavaScript
- JAVA 異常處理Java
- 異常的處理
- golang - 異常處理Golang
- 異常處理2
- 異常處理1
- Java 異常處理Java
- Abp 異常處理
- JAVA異常處理Java
- 08、異常處理
- SpringMVC異常處理SpringMVC
- 異常處理機制(二)之異常處理與捕獲
- Java 異常表與異常處理原理Java
- restframework 異常處理及自定義異常RESTFramework
- springboot下新增全域性異常處理和自定義異常處理Spring Boot
- Kotlin DSL C++專案引入OpenCV異常處理(轉)KotlinC++OpenCV
- NodeJS之異常處理NodeJS
- JAVA_異常處理Java
- React Native 異常處理React Native
- Spring Boot 異常處理Spring Boot
- PHP 核心 - 異常處理PHP
- GRpc異常處理FilterRPCFilter
- python異常捕捉處理Python