




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、第第9 9章章 異常處理異常處理 程序在運行過程中,由于用戶輸入錯誤、越界訪問和系統(tǒng)環(huán)境資源不足等原因,會導致程序運行不正?;虮罎?。程序在設計時必須考慮軟件的容錯能力,即應對運行時可能出現(xiàn)錯誤的位置和錯誤處理方法。在大型應用軟件中,相當一部分代碼是用于處理程序異常狀況的,異常處理是程序的重要組成部分。C+語言的異常處理機制能有效地進行異常檢測、異常拋出、異常捕獲和異常處理,成為提高程序穩(wěn)鍵性的重要手段之一。 本章主要學習異常的拋出和捕獲方法、堆棧展開、重新拋出異常、異常與繼承以及標準庫中的異常類等知識。 9.1 9.1 異常概述異常概述9.2 9.2 異常處理機制異常處理機制9.3 9.3 構
2、造函數(shù)、析構函數(shù)和異常構造函數(shù)、析構函數(shù)和異常9.4 9.4 標準庫的異常類層次結構標準庫的異常類層次結構9.5 9.5 案例實訓案例實訓第第9 9章章 異常處理異常處理9.1 9.1 異常概述異常概述 程序在設計和運行過程中均可能出現(xiàn)各式各樣的錯誤,依據(jù)錯誤產生的原因,主要分為3類:語法錯誤、邏輯錯誤和運行錯誤。l 語法錯誤是程序在編譯、連接時,編譯器報告的錯誤。此類錯誤產生的原因主要是程序結構不合規(guī)則、變量沒有定義、拼寫錯誤或缺少相關文件等。編譯器基本上能正確指出這類錯誤的位置,修改也比較簡單。l 邏輯錯誤是程序能正常編譯、連接并運行,但結果錯誤或偶爾報錯。此類錯誤是由算法設計有誤或考慮問
3、題不周全等因素引起,通過調試或測試,通常能查找出錯誤的原因。l 運行錯誤是程序在執(zhí)行過程中錯誤的輸入或運行環(huán)境沒有滿足等因素,導致程序非正常終止。運行錯誤雖然是由于軟件在使用過程中用戶使用不當或環(huán)境資源不足等外在因素引起的,但通??梢允孪阮A料。 異常處理(Exception Handling)就是在運行時刻對運行錯誤進行檢測、捕獲和提示等過程。傳統(tǒng)的C語言處理運行時錯誤的方法是用if-else語句檢測處理可能發(fā)生的異常,其特征是測試程序是否被正確地執(zhí)行。如果不是,則執(zhí)行錯誤處理代碼,否則繼續(xù)運行。雖然這種方式的異常處理也能滿足設計要求,但是程序的正常處理流程和錯誤處理邏輯混合在一起,正常的程序
4、流程被“淹沒”在異常判斷與處理之中,增加了閱讀、修改和維護程序的難度,在多人合作開發(fā)的大型軟件中該問題更加突出。9.1 9.1 異常概述異常概述9.2 9.2 異常處理機制異常處理機制 異常處理作為C+語言的一部分,引入了關鍵字try(檢測異常)、throw(拋出異常)和catch(捕獲異常)。在函數(shù)中檢測到某種錯誤發(fā)生后,函數(shù)自己并不處理異常,而是由throw語句引發(fā)并拋出異常,僅告知調用函數(shù)發(fā)生了什么異常。在調用函數(shù)中用try-catch語句檢測異常并處理。如果拋出的異常沒有被調用函數(shù)捕獲處理,異常就被傳遞到更高一層的函數(shù)調用,最后到達主函數(shù)。9.2 9.2 異常處理機制異常處理機制9.2
5、.1 異常的拋出 拋出異常的語法格式為: throw 表達式 如果在某段程序中檢測到可能發(fā)生的異常,則用throw語句拋出表達式的值作為發(fā)生的異常,異常的數(shù)據(jù)類型是異常捕獲的依據(jù)。若函數(shù)執(zhí)行了throw語句,則其后的語句將不再執(zhí)行,程序流程將返回到調用函數(shù),其功能與return語句相似。 拋出的異常在調用函數(shù)中捕獲并處理,調用函數(shù)中需要用try-catch結構語句來捕獲異常并處理?!纠?-1】零為除數(shù)的異常處理。9.2 9.2 異常處理機制異常處理機制程序說明: (1)從運行結果可知,程序運行到divide(34, 0)時,函數(shù)拋出了異常,并被第2個catch塊捕獲,輸出錯誤提示信息。try塊
6、中的后面兩個語句均沒有被執(zhí)行,程序正常結束。try塊后面的catch塊有兩個。由于divide函數(shù)拋出的值是int類型,故與第2個catch塊相匹配。異常捕獲的匹配原則是拋出的表達式的數(shù)據(jù)類型與catch塊聲明的類型是否一致。 (2)如果通過注釋符消除divide函數(shù)中throw語句的作用,則運行程序時將出現(xiàn)如圖9-1所示的對話框。如果在主函數(shù)中去除try和catch語句,則程序因沒有捕獲和處理異常語句,在運行時將彈出調試對話框。9.2 9.2 異常處理機制異常處理機制【例9-2】允許錯誤輸入的計算三角形面積程序。程序說明: (1)運行時輸入的第一行數(shù)據(jù)2、6、9為不能構成三角形的錯誤數(shù)據(jù),程
7、序能給出錯誤提示并繼續(xù)運行。異常處理機制使得程序具有容錯能力。 (2)throw string(“錯誤:三角形兩邊之和不能小于第三邊?!?語句中的string不能少,否則程序會因異常類型不匹配而終止。9.2 9.2 異常處理機制異常處理機制9.2.2 異常的捕獲與處理try-catch語句是專門用于捕獲處理異常的語句,其格式如下:try catch( ) catch( ) catch(.) 9.2 9.2 異常處理機制異常處理機制說明:(1)try子句中的程序段稱為受保護代碼塊(又稱try代碼塊),該代碼塊中包含可能引發(fā)異常的代碼。異??赡苁怯蓆ry代碼塊中的代碼直接產生,也可能是由于調用其他
8、函數(shù)產生的,或者由于代碼塊中的代碼啟動的深層嵌套函數(shù)調用產生的。try代碼塊中直接或間接地存在可能拋出異常的throw語句。(2)緊隨try子句之后是catch子句,一個try子句可以有多個catch子句。通常每個catch子句僅能捕獲一類異常,catch子句的括號中只能有一種異常類型和一個異常變量,用于指明該子句所捕獲的異常類型和接受所捕獲對象或值。catch(.)是能匹配任何異常類型的catch子句,不過它不能判別所捕獲的異常類型和具體的異常變量值,故不能提供準確的錯誤信息,在多個catch子句中通常它排在最后。9.2 9.2 異常處理機制異常處理機制如果用兩個及以上不同的catch子句捕
9、獲同一種類型的異常,則會產生編譯時錯誤。(3)catch子句捕獲異常后,對應異常處理代碼將被執(zhí)行。通常處理代碼所完成的操作有:給出錯誤提示、資源回收、消除出錯影響、重新拋出異常等。(4)try-catch語句僅適合處理異常,并不對程序的正常流程產生作用。此外,catch子句只能捕獲由其自身所在異常處理塊引發(fā)的異常。(5)如果拋出的異常沒有找到相匹配的catch子句,則該異常將被傳遞到外層作用域,即調用該異常處理模塊的主調函數(shù)。9.2 9.2 異常處理機制異常處理機制【例9-3】求一元二次方程的根,用異常進行容錯處理。 9.2 9.2 異常處理機制異常處理機制程序說明:(1)C+語言中,對結構體
10、類型進行了擴充。與類類型相似,既可以定義數(shù)據(jù)成員,也可以定義成員函數(shù)。它們的差別僅僅是結構體默認的訪問控制為public,而類為private。例程中root結構體用于記錄方程的根,并重載了流輸出運算符。(2)while(cin a b c)循環(huán)語句中用數(shù)據(jù)輸入語句cin a b c為判別條件。Z是流結束標志,當cin從輸入緩沖中檢測到Z,則返回0,于是程序結束循環(huán)。事實上,如果輸入任何一個非數(shù)值字母,由于字母不是實型數(shù),cin也返回0,循環(huán)同樣結束。9.2 9.2 異常處理機制異常處理機制9.2.3 重新拋出異常與堆棧展開 catch子句捕獲異常后,有可能不能完全處理該異常,此時catch子
11、句在完成一些自己的處理后,可以將該異常重新拋出(Rethrow),把異常傳遞給函數(shù)調用鏈中上一級的try-catch代碼塊進行捕獲處理。如果上一級調用函數(shù)沒有捕獲從被調函數(shù)傳遞的異?;蛘呔蜎]有try-catch語句,則該異常被傳遞到更上一級的catch子句,這種傳遞終止于主函數(shù)。如果主函數(shù)也沒有處理該異常,則調用在C+標準庫中定義的函數(shù)terminate()函數(shù)終止程序。l 重新拋出異常語句為空throw語句,即throw;語句。l 拋出的異常沿著逆函數(shù)調用鏈向上傳遞,終止于捕獲并處理異常的函數(shù)。 9.2 9.2 異常處理機制異常處理機制l 在函數(shù)調用與被調用的過程中,程序形成了一個函數(shù)調用鏈
12、。在程序的堆棧區(qū),調用函數(shù)的活動記錄和自動變量依照函數(shù)調用鏈的順序壓入堆棧。如果被拋出的異常在當前函數(shù)中沒有捕獲處理或重新拋出該異常,則函數(shù)調用堆棧便被“展開”,當前函數(shù)將終止執(zhí)行,自動變量被銷毀,活動記錄被彈出,流程返回到上一級調用函數(shù)。從本質上說,堆棧展開(Stack Unwinding )是異常處理的核心技術。l 堆棧在展開期間,函數(shù)將結束執(zhí)行,編譯器能保證釋放異常發(fā)生之前所創(chuàng)建的局部對象。如果局部對象是類類型的,則自動調用該對象的析構函數(shù)。l 異常使用不當可能導致動態(tài)內存空間“泄漏”。如果函數(shù)執(zhí)行過程中,已用new創(chuàng)建一個對象,但在用delete撤消該對象之前引發(fā)了異常,程序控制流程離
13、開了當前函數(shù),指向動態(tài)對象的指針隨著堆棧展開被清除,而動態(tài)內存中的對象卻不能自動回收,就會造成內存泄漏。9.2 9.2 異常處理機制異常處理機制下面的程序將導致動態(tài)內存空間釋放語句沒有執(zhí)行:#include using namespace std;double divide(double *m, double *n) if(*n) = 0)throw n;return *m/(*n);int main() try double *pm = new double(100);double *pn = new double(0);cout *pm / *pn = divide(pm,pn) endl
14、;delete pm;delete pn;catch(double *exp) cout 分母不能為 *exp endl;return 0;9.2 9.2 異常處理機制異常處理機制l 當異常處理模塊在接收到一個異常時,可能無法或只能部分處理該異常,此時異常處理代碼模塊可以拋出該異常。下面的例子演示了異常重新拋出和terminate()終止函數(shù)的用法?!纠?-4】重新拋出異常。9.2 9.2 異常處理機制異常處理機制程序說明:(1) 程序中,主函數(shù)調用functionA(),functionA()調用了functionB(),functionB()又調用functionC()。函數(shù)functio
15、nC()產生的異常被重新拋出,該異常沿逆函數(shù)調用鏈一直傳遞到主函數(shù)。 函數(shù)functionB()沒有捕獲函數(shù)functionC重新拋出的異常,異常直接傳遞到函數(shù)functionA。函數(shù)functionA的處理代碼僅輸出了字符串,又重新拋出異常。在主函數(shù)中輸出傳遞的異常內容后,也同樣拋出該異常。(2) 主函數(shù)調用terminate函數(shù)處理異常,該函數(shù)默認是調用系統(tǒng)的abort()函數(shù)。如圖9-2所示為terminate函數(shù)調用abort()函數(shù)出現(xiàn)的錯誤提示對話框。9.2 9.2 異常處理機制異常處理機制l 去除程序中的注釋符,即讓函數(shù)ending()和set_terminate()生效,再執(zhí)行
16、程序,運行結果在最后一行顯示“程序異常結束!”信息,不再彈出如圖9-2所示的對話框。(3)函數(shù)functionA()中的cout“函數(shù)A調用了函數(shù)B!”,使用戶可以像使用普通指針一樣使用auto_ptr對象。l auto_ptr對象被稱為智能指針,它解決了異??赡軐е聝却嫘孤┑膯栴}。但是,它并不是完美無缺的,一般不能用它指向數(shù)組,更不要將auto_ptr對象作為STL容器的元素。在新的C+標準中,shared_ptr將作為更好的方案,用于替代auto_ptr。l 程序運行時,系統(tǒng)分配給程序的動態(tài)內存空間是有限的。當new運算符執(zhí)行失敗時,C+標準規(guī)定將拋出一個bad_alloc異常。Visua
17、l C+ 2010支持該標準,但早期的Visual C+ 6.0在new失敗時只是返回0。9.3 9.3 構造函數(shù)、析構函數(shù)和異常構造函數(shù)、析構函數(shù)和異?!纠?-5】在構造函數(shù)中引發(fā)異常和auto_ptr應用。9.3 9.3 構造函數(shù)、析構函數(shù)和異常構造函數(shù)、析構函數(shù)和異常程序說明: (1)程序中定義了一個用于描述動物信息的類AnimalInfo,分別用于存儲動物圖片、叫聲和視頻的3個類(Picture、Sound、Video)均使用了動態(tài)存儲空間,并且為能引發(fā)異常申請了較大的內存空間。 所有的類均遵循:在構造函數(shù)中,用new運算符申請分配內存空間。在析構函數(shù)中,用delete運算符釋放內存空
18、間。從程序運行結果可知,程序在創(chuàng)建“獅子”對象時,執(zhí)行到video = new Video;語句拋出了bad_alloc異常。此時獅子對象Picture和Sound子對象已被創(chuàng)建,但它們的析構函數(shù)因異常的拋出而沒有執(zhí)行,引發(fā)內存泄漏。 “大象”對象因已完全構造,其析構函數(shù)正常運行,不受異常影響,故不存在內存泄漏。9.3 9.3 構造函數(shù)、析構函數(shù)和異常構造函數(shù)、析構函數(shù)和異常(2)2)運行結果的最后一行內容運行結果的最后一行內容bad allocationbad allocation為為bad_allocbad_alloc異常返回的信息。異常返回的信息。(3)(3)程序中給出了程序中給出了An
19、imalInfoAnimalInfo類的另一種實現(xiàn)。去除注釋類的另一種實現(xiàn)。去除注釋/ /* *和和* */ /,為前面的,為前面的AnimalInfoAnimalInfo類實現(xiàn)加上注釋。運行程序,得到下面的結果:類實現(xiàn)加上注釋。運行程序,得到下面的結果:call Picture Constructor.call Sound Constructor.call Video Constructor.大象對象調用AnimalInfo構造函數(shù)。call Picture Constructor.call Sound Constructor.call Sound Destructor.call Pictu
20、re Destructor.大象對象調用AnimalInfo析構函數(shù)。call Video Destructor.call Sound Destructor.call Picture Destructor.bad allocation9.3 9.3 構造函數(shù)、析構函數(shù)和異常構造函數(shù)、析構函數(shù)和異常l 從該結果可見,程序也是在為“獅子”對象分配Video空間時發(fā)生bad_alloc異常,但沒有產生內存泄漏,因為Sound和Picture類的析構函數(shù)均被執(zhí)行,釋放了已分配的內存。l 析構函數(shù)的作用是釋放對象構造時所占用的資源,那么析構函數(shù)中拋出異常將會發(fā)生什么呢?當程序在為某個異常進行堆棧展開時,
21、析構函數(shù)如果再拋出異常,將會導致調用標準庫中的terminate函數(shù),通常再引發(fā)調用abort函數(shù),使程序非正常終止。9.4 9.4 標準庫的異常類層次結構標準庫的異常類層次結構 C+的異常類型既可以是int、double等基本數(shù)據(jù)類型,也可以是結構體、類等用戶自定義的構造數(shù)據(jù)類型。程序中如果用基本數(shù)據(jù)類型表示異常,存在異常含義難以區(qū)分的問題。例如,程序中不能多處拋出含有不同語義的int類型異常,否則將難以區(qū)分這些異常的含義。 良好的編程規(guī)范是利用類的繼承性構建一個異常類型的架構,對錯誤進行歸類和描述。在C+的標準庫中定義了一個異常類層次,其結構如圖9-3所示。9.4 9.4 標準庫的異常類層
22、次結構標準庫的異常類層次結構9.4 9.4 標準庫的異常類層次結構標準庫的異常類層次結構 C+標準庫的異常類分別定義在4個頭文件中:頭文件中定義了異常類exception;頭文件中定義了runtime_error和logic_error異常類及其子類;頭文件中定義了bad-alloc異常類;頭文件中定義了bad_cast異常類。 exception異常類包含了虛函數(shù)what(),在派生類中可以對其重新定義,生成相應的錯誤消息?;恊xception只通知異常的產生,不提供更多的信息。 runtime_error異常類用于描述在運行時才能檢測到的錯誤,它派生了以下3個子類:l range_err
23、or:該異常類用于描述結果超出了有意義的值域范圍。l overflow_error:該異常類用于表示計算上溢。l underflow_error:該異常類用于描述計算下溢。9.4 9.4 標準庫的異常類層次結構標準庫的異常類層次結構l logic_error異常類表示邏輯錯誤,用來描述在程序運行前檢測到的錯誤。logic_error的派生類domain_error異常類表示參數(shù)的結果值不存在;invalid_argument異常類表示不合適的參數(shù);length_error異常類用于描述試圖生成一個超出該類型最大長度的對象;out_of_range異常類表示使用了一個超出有效范圍的值。l bad
24、_alloc異常類用于描述因無法分配內存而由new拋出的異常。l bad_cast異常類是在dynamic_cast失敗時拋出該異常類對象,dynamic_cast運算符的作用是進行類型轉換,dynamic_cast主要用于類層次間的上行轉換和下行轉換,還可以用于類之間的交叉轉換。l 標準異常類可以直接應用于程序中,也可以在已定義的異常類之上派生出自定義的異常類型。l 順序表是一種重要的數(shù)據(jù)結構,它使用一塊連續(xù)的內存空間保存數(shù)據(jù)元素,并用元素所存儲的物理位置來表示元素之間的先后關系。順序表在創(chuàng)建和使用時可能因自由存儲空間不足出現(xiàn)異常,可能由于訪問、插入或刪除操作所指定的位置錯誤出現(xiàn)訪問錯誤,也可能因存儲空間已滿,不能再插入新元素,需要引發(fā)異常?!纠?-6】標準異常類應用。設計具有異常處理功能的順序表類。9.4 9.4 標準庫的異常類層次結構標準庫的異常類層次結構程序說明:(1) 在SeqList類的I
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 土木工程材料??荚囶}+參考答案
- 個人工作實習心得體會
- 單獨中介合同范本
- 兌房押金合同范例
- epc合同和總包合同范本
- 三年級下學期語文教學總結
- 中式烹調師中級練習題及參考答案
- 養(yǎng)殖蚯蚓合同范本
- 單獨招生機電類復習題
- 七色花幼兒教學反思
- 壓力容器考試審核考試題庫(容標委氣體協(xié)會聯(lián)合)
- 人教版(2025版)七年級下冊英語UNIT 1 Animal Friends 單元整體教學設計(6個課時)
- 2025年春季學期學校德育工作計劃及安排表
- 2025年山東商務職業(yè)學院高職單招語文2018-2024歷年參考題庫頻考點含答案解析
- 校園體育活動的多元化與健康促進
- 新中式養(yǎng)生知識培訓課件
- 山東省臨沂市地圖矢量課件模板()
- 學習2025年全國教育工作會議心得體會
- Gly-Gly-Leu-生命科學試劑-MCE
- 零售業(yè)的門店形象提升及店面管理方案設計
- 高速公路40m連續(xù)T梁預制、架設施工技術方案
評論
0/150
提交評論