1. 程式人生 > >C++處理異常 try,catch,throw

C++處理異常 try,catch,throw

內容導讀:
本文包括2個大的異常實現概念:C++的標準異常和SHE異常。

C++標準異常:也許我們瞭解過他,但你有考慮過,其實你根本不會使用,你不相信,那我問你:垃圾回收在C++中怎麼實現?其實不需要實現,C++已經有了,但是你不會用,那麼從<構造和析構中的異常丟擲>開始看把。也許很高興看到錯誤之後的Heap/Stack中物件被釋放,可是如果沒有呢?有或者試想一下一個能解決的錯誤,需要我們把整個程式Kill掉嗎?
 在C++標準異常中我向你推薦這幾章:<使用異常規格程式設計> <構造和析構中的異常丟擲>  <使用解構函式防止資源洩漏> 以及一個深點的<丟擲一個異常的行為>


SHE異常: 我要問你你是一個WIN32程式設計師嗎?如果不是,那麼也許你真的不需要看
這塊內容了,SHE是Windows的結構化異常,每一個WIN32程式設計師都應該要掌握它。SHE功能強大,包括Termination handling和Exception handling兩大部分,強有力的維護了程式碼的健壯,雖然要以部分系統效能做犧牲(其實可以避免)。在SHE中有大量的程式碼,已經在Win平臺上測試過了。
這裡要提一下:在__finally處理中編譯器參與了絕大多數的工作,而Exception則是OS接管了幾乎所有的工作,也許我沒有提到的是:對__finally來說當遇到ExitThread/ExitProcess/abort等函式時,finally塊不會被執行。另,我們的程式碼使用軟體異常是比return error message好2**32的方法。


另,《使用解構函式防止資源洩漏》這個節點引用了More effective C++的條款9,用2個列子,講述了我們一般都會犯下的錯誤,往往這種錯誤是我們沒有意識到的但確實是會給我們的軟體帶來致命的Leak/Crash,但這是有解決的方法的,那就是使用“靈巧指標”。

如果對照<More effective C++>的37條條款,關於異常的高階使用,有以下內容是沒有完成的:
l 使用建構函式防止資源Leak(More effective C++ #10)
l 禁止異常資訊傳遞到析構Function外 (More effective C++ #11)
l 通過引用捕獲異常 (More effective C++ #13)

l 謹慎使用異常規格  (More effective C++ #14)
l 瞭解異常處理造成的系統開銷 (More effective C++ #15)
l 限制物件數量 (More effective C++ #26)
l 靈巧指標 (More effective C++ #28)
[宣告:節點:<使用解構函式防止資源洩漏> 和 節點:<丟擲一個異常的行為>中有大量的關於More effective C++的條款,所以本文擋只用於自我閱讀和內部交流,任何公開化和商業化,事先宣告與本人無關。]

C++異常
C++引入異常的原因
C++新增的異常機制改變了某些事情,這些改變是徹底的,但這些改變也可能讓我們不舒服。例如使用未經處理的pointer變的很危險,Memory/Resource Leak變的更有可能了(別說什麼Memory便宜了,那不是一個優秀的程式設計師說的話。),寫出一個具有你希望的行為的建構函式和解構函式也變的困難(不可預測),當然最危險的也許是我們寫出的東東狗屁了,或者是速度變慢了。

大多數的程式設計師知道Howto use exception 來處理我們的程式碼,可是很多人並不是很重視異常的處理(國外的很多Code倒是處理的很好,Java的Exception機制很不錯)。異常處理機制是解決某些問題的上佳辦法,但同時它也引入了許多隱藏的控制流程;有時候,要正確無誤的使用它並不容易。

在異常被throw後,沒有一個方法能夠做到使軟體的行為具有可預測性和可靠性(這句話不是我說的,是Jack Reeves寫的Coping with Exception和Herb Sutter寫的Exception-Safe Generic Containers中的。)一個沒有按照異常安全設計的程式想Run 正常,是做夢,別去想沒有異常出現的可能,

對C程式來說,使用Error Code就可以了,為什麼還要引入異常?因為異常不能被忽略。如果一個函式通過設定一個狀態變數或返回錯誤程式碼來表示一個異常狀態,沒有辦法保證函式呼叫者將一定檢測變數或測試錯誤程式碼。結果程式會從它遇到的異常狀態繼續執行,異常沒有被捕獲,程式立即會終止執行。

在C程式中,我們可以用int setjmp( jmp_buf env );和 void longjmp( jmp_buf env, int value );這2個函式來完成和異常處理相識的功能,但是MSDN中介紹了在C++中使用longjmp來調整stack時不能夠對區域性的物件呼叫解構函式,但是對C++程式來說,解構函式是重要的(我就一般都把物件的Delete放在解構函式中)。
所以我們需要一個方法:①能夠通知異常狀態,又不能忽略這個通知,②並且Searching the stack以便找到異常程式碼時,③還要確保區域性物件的解構函式被Call。而C++的異常處理剛好就是來解決這些問題的。

有的地方只有用異常才能解決問題,比如說,在當前上下文環境中,無法捕捉或確定的錯誤型別,我們就得用一個異常丟擲到更大的上下文環境當中去。還有,異常處理的使用呢,可以使出錯處理程式與“通常”程式碼分離開來,使程式碼更簡潔更靈活。另外就是程式必不可少的健壯性了,異常處理往往在其中扮演著重要的角色。

C++使用throw關鍵字來產生異常,try關鍵字用來檢測的程式塊,catch關鍵字用來填寫異常處理的程式碼。異常可以由一個確定類或派生類的物件產生。C++能釋放堆疊,並可清除堆疊中所有的物件。

C++的異常和pascal不同,是要程式設計師自己去實現的,編譯器不會做過多的動作。

throw異常類程式設計
丟擲異常用throw, 如:
throw ExceptionClass(“my throw“);

例句中,ExceptionClass是一個類,它的建構函式以一個字串做為引數。也就是說,在throw的時候,C++的編譯器先構造一個ExceptionClass的物件,讓它作為throw的值丟擲去。同時,程式返回,呼叫析構。看下面這個程式:
  1. #include <iostream.h>
  2. class ExceptionClass{  
  3.        char* name;  
  4. public:  
  5.   ExceptionClass(constchar* name="default name")   
  6.   {  
  7.     cout<<"Construct "<<name<<endl;  
  8.     this->name=name;  
  9.   }  
  10.   ~ExceptionClass()  
  11.   {  
  12.     cout<<"Destruct "<<name<<endl;  
  13.   }  
  14.   void mythrow()  
  15.   {  
  16.     throw ExceptionClass("my throw");  
  17.   }  
  18. }  
  19. void main(){  
  20.   ExceptionClass e("Test");  
  21.    try{  
  22.         e.mythrow();  
  23.       }   
  24.   catch(...)  
  25.   {  
  26.     cout<<”*********”<<endl;  
  27.   }  
  28. }  

這是輸出資訊:
Construct Test
Construct my throw
Destruct my throw
****************
Destruct my throw   (這裡是異常處理空間中對異常類的拷貝的析構)
Destruct Test
======================================
不過一般來說我們可能更習慣於把會產生異常的語句和要throw的異常類分成不同的類來寫,下面的程式碼可以是我們更願意書寫的:
  1. ………..  
  2. class ExceptionClass{  
  3.   public:  
  4.     ExceptionClass(constchar* name="Exception Default Class"){  
  5.       cout<<"Exception Class Construct String"<<endl;  
  6.     }  
  7.     ~ExceptionClass(){  
  8.       cout<<"Exception Class Destruct String"<<endl;  
  9.     }  
  10.     void ReportError() {  
  11.       cout<<"Exception Class:: This is Report Error Message"<<endl;  
  12.     }  
  13. };  
  14. class ArguClass{  
  15.   char* name;  
  16. public:  
  17.   ArguClass(char* name="default name"){  
  18.     cout<<"Construct String::"<<name<<endl;  
  19.     this->name=name;  
  20.   }  
  21.   ~ArguClass(){  
  22.     cout<<"Destruct String::"<<name<<endl;  
  23.   }  
  24.   void mythrow(){  
  25.     throw ExceptionClass("my throw");  
  26.   }         
  27. };  
  28. _tmain()  
  29. {  
  30.   ArguClass e("haha");  
  31.   try {  
  32.     e.mythrow();  
  33.   }   
  34.   catch(int)  
  35.   {  
  36.     cout<<"If This is Message display screen, This is a Error!!"<<endl;  
  37.   }  
  38.   catch(ExceptionClass pTest)   
  39.   {  
  40.     pTest.ReportError();  
  41.   }  
  42.   catch(...){  
  43.     cout<<"***************"<<endl;    
  44.   }  
  45. }  

輸出Message:
Construct String::haha
Exception Class Construct String
Exception Class Destruct String
Exception Class:: This is Report Error Message
Exception Class Destruct String
Destruct String::haha
使用異常規格程式設計
如果我們呼叫別人的函式,裡面有異常丟擲,用去檢視它的原始碼去看看都有什麼異常丟擲嗎?這樣就會很煩瑣。比較好的解決辦法,是編寫帶有異常丟擲的函式時,採用異常規格說明,使我們看到函式宣告就知道有哪些異常出現。

異常規格說明大體上為以下格式:
void ExceptionFunction(argument…) throw(ExceptionClass1, ExceptionClass2, ….)
所有異常類都在函式末尾的throw()的括號中得以說明了,這樣,對於函式呼叫者來說,是一清二楚的。

注意下面一種形式:
void ExceptionFunction(argument…) throw()
表明沒有任何異常丟擲。
而正常的void ExceptionFunction(argument…)則表示:可能丟擲任何一種異常,當然,也可能沒有異常,意義是最廣泛的。

異常捕獲之後,可以再次丟擲,就用一個不帶任何引數的throw語句就可以了。
構造和析構中的異常丟擲
這是異常處理中最要注意的地方了

先看個程式,假如我在建構函式的地方丟擲異常,這個類的析構會被呼叫嗎?可如果不呼叫,那類裡的東西豈不是不能被釋放了?
  1. #include <iostream.h>
  2. #include <stdlib.h>
  3. class ExceptionClass1  
  4. {  
  5.   char* s;  
  6. 相關推薦

    C++處理異常 try,catch,throw

    內容導讀: 本文包括2個大的異常實現概念:C++的標準異常和SHE異常。 C++標準異常:也許我們瞭解過他,但你有考慮過,其實你根本不會使用,你不相信,那我問你:垃圾回收在C++中怎麼實現?其實不需要實現,C++已經有了,但是你不會用,那麼從<構造和析構中的異常丟擲>開始看把。也許很高

    c#】異常處理try catch throw

            異常處理,是程式語言或計算機硬體裡的一種機制,用於處理軟體或資訊系統中出現的異常狀況(即超出程式正常執行流程的某些特殊條件)。 也就是說,在程式執行時出現的任何意外或異常情況時,處理這種意外或情況的方法,叫做異常處理。  

    C++異常處理try,catch,throw,finally的用法

    很多window系統有C-like介面,使用象like createWindow 和 destroyWindow函式來獲取和釋放window資源. 如果在w對應的window中顯示資訊時,一個異常被丟擲,w所對應的window將被丟失,就象其它動態分配的資源一樣. 解決方法與前面所述的一樣,建立一個類

    Java基礎 內部類 異常try catch throw RuntimeException

    內部類 將一個類定義在另一個類的裡面,對裡面那個類就稱為內部類(內建類,巢狀類)。 訪問特點: 內部類可以直接訪問外部類中的成員,包括私有成員。 而外部類要訪問內部類中的成員必須要建立內部類的物件。 內部類訪問規則 內部類可以直接訪問外部類中的

    C++異常處理 try-catch throw

    try-catch throw 示意圖 throw 介紹 出現異常時發出一個異常資訊 throw 離開後,流程立即離開本函式 throw a;throw b;等等作用相同 throw 找不到與之匹配的catch塊時,系統會呼叫terminate終止程式

    C++ 異常捕捉與處理try...catch...)

    首先舉一個異常處理的例子: string str = "0123456789"; char ch1 = str[100];    //陣列越界,但是不提醒,程式執行立即崩潰 cout << ch1 << endl;    &n

    關於對Java中異常處理try catchthrow的理解(淺顯理解)

    一.try catch方法   A.什麼try catch 方法     try catch是異常處理中一種方法,檢測並捕捉異常然後進行處理     try是檢測異常,catch是捕捉異常   B try catch的三種格式   格式1   try{     語句體;   }catch{    

    java中的異常處理try catch塊的簡單應用

    java中的異常根據是否需要人為處理分為倆種: A:非受查異常:派生於Error類,與RuntimeException類(執行時異常)的所有異常。 B:受查異常----:所有不屬於非受查異常類的異常(包

    PHP5的異常處理機制 — Try-catch 語句

    為了進一步處理異常,我們需要使用try-catch語句—包括Try語句和至少一個的catch語句。任何呼叫 可能丟擲異常的方法的程式碼都應該使用try語句。Catch語句用來處理可能丟擲的異常。以下顯示了我們處理getCommandObject()丟擲的異常的方法: &

    scala:異常處理try/catch

    處理語法: try { // ... } catch { case ex: Exception => { ex.printStackTrace() // 列印到標準err System.err.println("exception==

    Java異常處理try{}catch丟擲異常,後面程式碼還會繼續執行麼?

    這張圖片上面顯示的程式碼執行之後將會輸出什麼?我們可以發現在procedure()函式結束之後函式後面的內容就不運行了,而主函式裡面的程式還是會繼續執行。反過來再測試如果先發生主函式裡面的異常那麼Pr

    異常處理try-catch-finally語句

    try{ // 可能會丟擲特定異常的程式碼段}catch(MyExceptionType  myException){ // 如果myException 被丟擲,則執行這段程式碼}catch(Exception otherException){//如果另外的異常otherEx

    Java異常處理try,catch,finally的各種組合用法

    1.try+catch 程式的流程是:執行到try塊中,如果有異常丟擲,則轉到catch塊去處理。然後執行catch塊後面的語句  2.try+catch+finally 程式的流程是:執行到try

    C語言實現try catch處理

    我們都知道,在Java、C#等高階程式語言中,都自帶有異常處理機制,其基本結構如下: try{ 程式語句; }catch(Exception ex){ 異常處理; } 這樣做不但可以防止程式異常終止,而且在出現錯誤時可以及時作一些釋放資源處理,對程式能繼續健壯的執行下去尤

    java的異常處理機制(trycatch…finally)

    1 引子 try…catch…finally恐怕是大家再熟悉不過的語句了,而且感覺用起來也是很簡單,邏輯上似乎也是很容易理解。不過,我親自體驗的“教訓”告訴我,這個東西可不是想象中的那麼簡單、聽話。不信?那你看看下面的程式碼,“猜猜”它執行後的結果會是什麼?不要往後看答案

    java異常 try-catchthrow

    異常處理1:try和catch捕獲異常 package com.MissXu.blogTest; import java.util.Scanner; public class Exception

    (筆記)異常處理try/catch的應用例子(finally待整理)

    題目:判斷傳入的字串是否為ip地址 /** * 判斷傳入的字串是否為ip地址 * @param ip * @return * @throws Exception */ public static boolean isIP(String ip)

    異常(try……catch……finally、throws和throw的區別、自定義異常)

    一、什麼是異常 什麼是異常? 認識異常:導致程式中斷執行的。 例如我們編寫了一個除法程式,除數是不可以為0的,但是我們一開始沒有做這個規定,如果執行的過程中出現了0,那麼程式就會異常結束。 二、try……catch和finally 出現異常的語句要怎麼

    異常處理方法 try catch finally

    try 程序 png info all 捕捉 12px ima finally try catch finally的用法 package com.異常; import java.util.InputMismatchException; import java.uti

    Java異常處理只有Try-Catch嗎?

    今天,我們將討論一個非常重要的主題-Java 中的異常處理。儘管有時可能會對此主題進行過多的討論,但並非每篇文章都包含有用且相關的資訊。 Java 中最常見的異常處理機制通常與 try-catch 塊關聯 。我們使用它來捕獲異常,然後提供在發生異常的情況下可以執行的邏輯。 的確,你不需要將所有異常都放在這些塊