青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

面對現(xiàn)實,超越自己
逆水行舟,不進則退
posts - 269,comments - 32,trackbacks - 0

一、什么是異常處理

        一句話:異常處理就是處理程序中的錯誤。

二、為什么需要異常處理,以及異常處理的基本思想

        C++之父Bjarne Stroustrup在《The C++ Programming Language》中講到:一個庫的作者可以檢測出發(fā)生了運行時錯誤,但一般不知道怎樣去處理它們(因為和用戶具體的應用有關);另一方面,庫的用戶知道怎樣處理這些錯誤,但卻無法檢查它們何時發(fā)生(如果能檢測,就可以再用戶的代碼里處理了,不用留給庫去發(fā)現(xiàn))。

        Bjarne Stroustrup說:提供異常基本目的就是為了處理上面的問題。基本思想是:讓一個函數(shù)在發(fā)現(xiàn)了自己無法處理的錯誤時拋出(throw)一個異常,然后它的(直接或者間接)調(diào)用者能夠處理這個問題。 
The fundamental idea is that a function that finds a problem it cannot cope with throws an exception, hoping that its (direct or indirect) caller can handle the problem.

        也就是《C++ primer》中說的:將問題檢測問題處理相分離。 
Exceptions let us separate problem detection from problem resolution

        一種思想:在所有支持異常處理的編程語言中(例如java),要認識到的一個思想:在異常處理過程中,由問題檢測代碼可以拋出一個對象給問題處理代碼,通過這個對象的類型和內(nèi)容,實際上完成了兩個部分的通信,通信的內(nèi)容是“出現(xiàn)了什么錯誤”。當然,各種語言對異常的具體實現(xiàn)有著或多或少的區(qū)別,但是這個通信的思想是不變的。

三、異常出現(xiàn)之前處理錯誤的方式

        在C語言的世界中,對錯誤的處理總是圍繞著兩種方法:一是使用整型的返回值標識錯誤;二是使用errno宏(可以簡單的理解為一個全局整型變量)去記錄錯誤。當然C++中仍然是可以用這兩種方法的。

        這兩種方法最大的缺陷就是會出現(xiàn)不一致問題。例如有些函數(shù)返回1表示成功,返回0表示出錯;而有些函數(shù)返回0表示成功,返回非0表示出錯。

        還有一個缺點就是函數(shù)的返回值只有一個,你通過函數(shù)的返回值表示錯誤代碼,那么函數(shù)就不能返回其他的值。當然,你也可以通過指針或者C++的引用來返回另外的值,但是這樣可能會令你的程序略微晦澀難懂。

四、異常為什么好

    在如果使用異常處理的優(yōu)點有以下幾點:

        1. 函數(shù)的返回值可以忽略,但異常不可忽略。如果程序出現(xiàn)異常,但是沒有被捕獲,程序就會終止,這多少會促使程序員開發(fā)出來的程序更健壯一點。而如果使用C語言的error宏或者函數(shù)返回值,調(diào)用者都有可能忘記檢查,從而沒有對錯誤進行處理,結(jié)果造成程序莫名其面的終止或出現(xiàn)錯誤的結(jié)果。

        2. 整型返回值沒有任何語義信息。而異常卻包含語義信息,有時你從類名就能夠體現(xiàn)出來。

        3. 整型返回值缺乏相關的上下文信息。異常作為一個類,可以擁有自己的成員,這些成員就可以傳遞足夠的信息。

        4. 異常處理可以在調(diào)用跳級。這是一個代碼編寫時的問題:假設在有多個函數(shù)的調(diào)用棧中出現(xiàn)了某個錯誤,使用整型返回碼要求你在每一級函數(shù)中都要進行處理。而使用異常處理的棧展開機制,只需要在一處進行處理就可以了,不需要每級函數(shù)都處理。

五、C++中使用異常時應注意的問題

    任何事情都是兩面性的,異常有好處就有壞處。如果你是C++程序員,并且希望在你的代碼中使用異常,那么下面的問題是你要注意的。

        1. 性能問題。這個一般不會成為瓶頸,但是如果你編寫的是高性能或者實時性要求比較強的軟件,就需要考慮了。

(如果你像我一樣,曾經(jīng)是java程序員,那么下面的事情可能會讓你一時迷糊,但是沒辦法,誰叫你現(xiàn)在學的是C++呢。)

       2. 指針和動態(tài)分配導致的內(nèi)存回收問題:在C++中,不會自動回收動態(tài)分配的內(nèi)存,如果遇到異常就需要考慮是否正確的回收了內(nèi)存。在java中,就基本不需要考慮這個,有垃圾回收機制真好!

        3. 函數(shù)的異常拋出列表:java中是如果一個函數(shù)沒有在異常拋出列表中顯式指定要拋出的異常,就不允許拋出;可是在C++中是如果你沒有在函數(shù)的異常拋出列表指定要拋出的異常,意味著你可以拋出任何異常

        4. C++中編譯時不會檢查函數(shù)的異常拋出列表。這意味著你在編寫C++程序時,如果在函數(shù)中拋出了沒有在異常拋出列表中聲明的異常,編譯時是不會報錯的。而在java中,eclipse的提示功能真的好強大啊!

        5. 在java中,拋出的異常都要是一個異常類;但是在C++中,你可以拋出任何類型,你甚至可以拋出一個整型。(當然,在C++中如果你catch中接收時使用的是對象,而不是引用的話,那么你拋出的對象必須要是能夠復制的。這是語言的要求,不是異常處理的要求)。

        6. 在C++中是沒有finally關鍵字的。而java和python中都是有finally關鍵字的。

六、異常的基本語法

1. 拋出和捕獲異常

        很簡單,拋出異常用throw,捕獲用try……catch

        捕獲異常時的注意事項:

             1. catch子句中的異常說明符必須是完全類型,不可以為前置聲明,因為你的異常處理中常常要訪問異常類的成員。例外:只有你的catch子句使用指針或者引用接收參數(shù),并且在catch子句內(nèi)你不訪問異常類的成員,那么你的catch子句的異常說明符才可以是前置聲明的類型。

             2. catch的匹配過程是找最先匹配的,不是最佳匹配。

             3. catch的匹配過程中,對類型的要求比較嚴格允許標準算術(shù)轉(zhuǎn)換類類型的轉(zhuǎn)換。(類類型的轉(zhuǎn)化包括種:通過構(gòu)造函數(shù)的隱式類型轉(zhuǎn)化和通過轉(zhuǎn)化操作符的類型轉(zhuǎn)化)。

             4. 和函數(shù)參數(shù)相同的地方有: 
                    ① 如果catch中使用基類對象接收子類對象,那么會造成子類對象分隔slice)為父類子對象(通過調(diào)用父類的復制構(gòu)造函數(shù)); 
                    ② 如果catch中使用基類對象的引用接受子類對象,那么對虛成員的訪問時,會發(fā)生動態(tài)綁定,即會多態(tài)調(diào)用。 
                    ③ 如果catch中使用基類對象的指針,那么一定要保證throw語句也要拋出指針類型,并且該指針所指向的對象,在catch語句執(zhí)行是還存在(通常是動態(tài)分配的對象指針)。

             5. 和函數(shù)參數(shù)不同的地方有:   
                    ① 如果throw中拋出一個對象,那么無論是catch中使用什么接收(基類對象、引用、指針或者子類對象、引用、指針),在傳遞到catch之前,編譯器都會另外構(gòu)造一個對象的副本。也就是說,如果你以一個throw語句中拋出一個對象類型,在catch處通過也是通過一個對象接收,那么該對象經(jīng)歷了兩次復制,即調(diào)用了兩次復制構(gòu)造函數(shù)。一次是在throw時,將“拋出到對象”復制到一個“臨時對象”(這一步是必須的),然后是因為catch處使用對象接收,那么需要再從“臨時對象”復制到“catch的形參變量”中; 如果你在catch中使用“引用”來接收參數(shù),那么不需要第二次復制,即形參的引用指向臨時變量。 
                    ② 該對象的類型與throw語句中體現(xiàn)的靜態(tài)類型相同。也就是說,如果你在throw語句中拋出一個指向子類對象的父類引用,那么會發(fā)生分割現(xiàn)象,即只有子類對象中的父類部分會被拋出,拋出對象的類型也是父類類型。(從實現(xiàn)上講,是因為復制到“臨時對象”的時候,使用的是throw語句中類型的(這里是父類的)復制構(gòu)造函數(shù))。 
                    ③ 不可以進行標準算術(shù)轉(zhuǎn)換類的自定義轉(zhuǎn)換:在函數(shù)參數(shù)匹配的過程中,可以進行很多的類型轉(zhuǎn)換。但是在異常匹配的過程中,轉(zhuǎn)換的規(guī)則要嚴厲。

                    ④ 異常處理機制的匹配過程是尋找最先匹配(first fit),函數(shù)調(diào)用的過程是尋找最佳匹配(best fit)。

2. 異常類型

        上面已經(jīng)提到過,在C++中,你可以拋出任何類型的異常。(哎,竟然可以拋出任何類型,剛看到到這個的時候,我半天沒反應過來,因為java中這樣是不行的啊)。

         注意:也是上面提到過的,在C++中如果你throw語句中拋出一個對象,那么你拋出的對象必須要是能夠復制的。因為要進行復制副本傳遞,這是語言的要求,不是異常處理的要求。(在上面“和函數(shù)參數(shù)不同的地方”中也講到了,因為是要復制先到一個臨時變量中)

3. 棧展開

        棧展開指的是:當異常拋出后,匹配catch的過程。

        拋出異常時,將暫停當前函數(shù)的執(zhí)行,開始查找匹配的catch子句。沿著函數(shù)的嵌套調(diào)用鏈向上查找,直到找到一個匹配的catch子句,或者找不到匹配的catch子句。

        注意事項:

               1. 在棧展開期間,會銷毀局部對象。

                     ① 如果局部對象是類對象,那么通過調(diào)用它的析構(gòu)函數(shù)銷毀。

                     ② 但是對于通過動態(tài)分配得到的對象,編譯器不會自動刪除,所以我們必須手動顯式刪除。(這個問題是如此的常見和重要,以至于會用到一種叫做RAII的方法,詳情見下面講述)

               2. 析構(gòu)函數(shù)應該從不拋出異常。如果析構(gòu)函數(shù)中需要執(zhí)行可能會拋出異常的代碼,那么就應該在析構(gòu)函數(shù)內(nèi)部將這個異常進行處理,而不是將異常拋出去。

                     原因:在為某個異常進行棧展開時,析構(gòu)函數(shù)如果又拋出自己的未經(jīng)處理另一個異常,將會導致調(diào)用標準庫 terminate 函數(shù)。而默認的terminate 函數(shù)將調(diào)用 abort 函數(shù),強制從整個程序非正常退出。

               3. 構(gòu)造函數(shù)中可以拋出異常。但是要注意到:如果構(gòu)造函數(shù)因為異常而退出,那么該類的析構(gòu)函數(shù)就得不到執(zhí)行。所以要手動銷毀在異常拋出前已經(jīng)構(gòu)造的部分。

4. 異常重新拋出

        語法:使用一個空的throw語句。即寫成: throw;   

        注意問題:

                ① throw;  語句出現(xiàn)的位置,只能是catch子句中或者是catch子句調(diào)用的函數(shù)中。 
                ② 重新拋出的是原來的異常對象,即上面提到的“臨時變量”,不是catch形參。 
                ③ 如果希望在重新拋出之前修改異常對象,那么應該在catch中使用引用參數(shù)。如果使用對象接收的話,那么修改異常對象以后,不能通過“重新拋出”來傳播修改的異常對象,因為重新拋出不是catch形參,應該使用的是 throw e;  這里“e”為catch語句中接收的對象參數(shù)。

5. 捕獲所有異常(匹配任何異常)

        語法:在catch語句中,使用三個點(…)。即寫成:catch (…)   這里三個點是“通配符”,類似 可變長形式參數(shù)。

        常見用法:與“重新拋出”表達式一起使用,在catch中完成部分工作,然后重新拋出異常。

6. 未捕獲的異常

        意思是說,如果程序中有拋出異常的地方,那么就一定要對其進行捕獲處理。否則,如果程序執(zhí)行過程中拋出了一個異常,而又沒有找到相應的catch語句,那么會和“棧展開過程中析構(gòu)函數(shù)拋出異常”一樣,會 調(diào)用terminate 函數(shù),而默認的terminate 函數(shù)將調(diào)用 abort 函數(shù),強制從整個程序非正常退出。

7. 構(gòu)造函數(shù)的函數(shù)測試塊

        對于在構(gòu)造函數(shù)的初始化列表中拋出的異常,必須使用函數(shù)測試塊(function try block)來進行捕捉。語法類型下面的形式:

  1. MyClass::MyClass(int i)  
  2. try :member(i) {  
  3.     //函數(shù)體  
  4. catch(異常參數(shù)) {  
  5.     //異常處理代碼  
  6. }  

        注意事項:在函數(shù)測試塊中捕獲的異常,在catch語句中可以執(zhí)行一個內(nèi)存釋放操作,然后異常仍然會再次拋出到用戶代碼中。

8. 異常拋出列表(異常說明 exception specification)

        就是在函數(shù)的形參表之后(如果是const成員函數(shù),那么在const之后),使用關鍵字throw聲明一個帶著括號的、可能為空的 異常類型列表。形如:throw ()  或者 throw (runtime_error, bad_alloc)   。

        含義:表示該函數(shù)只能拋出 在列表中的異常類型。例如:throw() 表示不拋出任何異常。而throw (runtime_error, bad_alloc)表示只能拋出runtime_error 或bad_alloc兩種異常。

        注意事項:(以前學java的尤其要注意,和java中不太一樣)

                ① 如果函數(shù)沒有顯式的聲明 拋出列表,表示異常可以拋出任意列表。(在java中,如果沒有異常拋出列表,那么是不能拋出任何異常的)。

                ② C++的 “throw()”相當于java的不聲明拋出列表。都表示不拋出任何異常。

                ③ 在C++中,編譯的時候,編譯器不會對異常拋出列表進行檢查。也就是說,如果你聲明了拋出列表,即使你的函數(shù)代碼中拋出了沒有在拋出列表中指定的異常,你的程序依然可以通過編譯,到運行時才會出錯,對于這樣的異常,在C++中稱為“意外異常”(unexpeced exception)。(這點和java又不相同,在java中,是要進行嚴格的檢查的)。 

        意外異常的處理: 
                如果程序中出現(xiàn)了意外異常,那么程序就會調(diào)用函數(shù)unexpected()。這個函數(shù)的默認實現(xiàn)是調(diào)用terminate函數(shù),即默認最終會終止程序。

        虛函數(shù)重載方法時異常拋出列表的限制 
                在子類中重載時,函數(shù)的異常說明 必須要比父類中要同樣嚴格,或者更嚴格。換句話說,在子類中相應函數(shù)的異常說明不能增加新的異常。或者再換句話說:父類中異常拋出列表是該虛函數(shù)的子類重載版本可以拋出異常列表的 超集

        函數(shù)指針中異常拋出列表的限制 
                 異常拋出列表是函數(shù)類型的一部分,在函數(shù)指針中也可以指定異常拋出列表。但是在函數(shù)指針初始化或者賦值時,除了要檢查返回值形式參數(shù)外,還要注意異常拋出列表的限制:源指針的異常說明必須至少和目標指針的一樣嚴格。比較拗口,換句話說,就是聲明函數(shù)指針時指定的異常拋出列表,一定要實際函數(shù)的異常拋出列表的超集。 如果定義函數(shù)指針時不提供異常拋出列表,那么可以指向能夠拋出任意類型異常的函數(shù)。                

        拋出列表是否有用   
                 在《More effective C++》第14條,Scott Meyers指出“要謹慎的使用異常說明”(Use exception specifications judiciously)。“異常說明”,就是我們所有的“異常拋出列表”。之所以要謹慎,根本原因是因為C++編譯器不會檢查異常拋出列表,這樣就可能在函數(shù)代碼中、或者調(diào)用的函數(shù)中拋出了沒有在拋出列表中指定的異常,從而導致程序調(diào)用unexpected函數(shù),造成程序提前終止。同時他給出了三條要考慮的事情: 
                         ① 在模板不要使用異常拋出列表。(原因很簡單,連用來實例模板的類型都不知道,也就無法確定該函數(shù)是否應該拋出異常,拋出什么異常)。  
                         ② 如果A函數(shù)內(nèi)調(diào)用了B函數(shù),而B函數(shù)沒有聲明異常拋出列表,那么A函數(shù)本身也不應該設定異常拋出列表。(原因是,B函數(shù)可能拋出沒有在A函數(shù)的異常拋出列表中聲明的異常,會導致調(diào)用unex函數(shù)); 
                         ③ 通過set_unexpected函數(shù)指定一個新的unexpected函數(shù),在該函數(shù)中捕獲異常,并拋出一個統(tǒng)一類型的異常。

                 另外,在《C++ Primer》4th 中指出,雖然異常說明應用有限,但是如果能夠確定該函數(shù)不會拋出異常,那么顯式聲明其不拋出任何異常 有好處。通過語句:"throw ()"。這樣的好處是:對于程序員,當調(diào)用這樣的函數(shù)時,不需要擔心異常。對于編譯器,可以執(zhí)行被可能拋出異常所抑制的優(yōu)化。

七、標準庫中的異常類

        和java一樣,標準庫中也提供了很多的異常類,它們是通過類繼承組織起來的。標準異常被組織成八個

        異常類繼承層級結(jié)構(gòu)圖如下: 
C++  標準庫異常類繼承層次圖

    每個類所在的頭文件在圖下方標識出來.

    標準異常類的成員: 
        ① 在上述繼承體系中,每個類都有提供了構(gòu)造函數(shù)、復制構(gòu)造函數(shù)、和賦值操作符重載。 
        ② logic_error類及其子類、runtime_error類及其子類,它們的構(gòu)造函數(shù)是接受一個string類型的形式參數(shù),用于異常信息的描述; 
        ③ 所有的異常類都有一個what()方法,返回const char* 類型(C風格字符串)的值,描述異常信息。

    標準異常類的具體描述 

異常名稱

描述

exception 所有標準異常類的父類
bad_alloc 當operator new and operator new[],請求分配內(nèi)存失敗時
bad_exception 這是個特殊的異常,如果函數(shù)的異常拋出列表里聲明了bad_exception異常,當函數(shù)內(nèi)部拋出了異常拋出列表中沒有的異常,這是調(diào)用的unexpected函數(shù)中若拋出異常,不論什么類型,都會被替換為bad_exception類型
bad_typeid 使用typeid操作符,操作一個NULL指針,而該指針是帶有虛函數(shù)的類,這時拋出bad_typeid異常
bad_cast 使用dynamic_cast轉(zhuǎn)換引用失敗的時候
ios_base::failure io操作過程出現(xiàn)錯誤
logic_error 邏輯錯誤,可以在運行前檢測的錯誤
runtime_error 運行時錯誤,僅在運行時才可以檢測的錯誤

        logic_error的子類: 

異常名稱

描述

length_error 試圖生成一個超出該類型最大長度的對象時,例如vector的resize操作
domain_error 參數(shù)的值域錯誤,主要用在數(shù)學函數(shù)中。例如使用一個負值調(diào)用只能操作非負數(shù)的函數(shù)
out_of_range 超出有效范圍
invalid_argument 參數(shù)不合適。在標準庫中,當利用string對象構(gòu)造bitset時,而string中的字符不是’0’或’1’的時候,拋出該異常

        runtime_error的子類: 

異常名稱

描述

range_error 計算結(jié)果超出了有意義的值域范圍
overflow_error 算術(shù)計算上溢
underflow_error 算術(shù)計算下溢

八、編寫自己的異常類

        1. 為什么要編寫自己的異常類? 
                ① 標準庫中的異常是有限的; 
                ② 在自己的異常類中,可以添加自己的信息。(標準庫中的異常類值允許設置一個用來描述異常的字符串)。

        2. 如何編寫自己的異常類? 
                ① 建議自己的異常類要繼承標準異常類。因為C++中可以拋出任何類型的異常,所以我們的異常類可以不繼承自標準異常,但是這樣可能會導致程序混亂,尤其是當我們多人協(xié)同開發(fā)時。 
                ② 當繼承標準異常類時,應該重載父類的what函數(shù)虛析構(gòu)函數(shù)。 
                ③ 因為棧展開的過程中,要復制異常類型,那么要根據(jù)你在類中添加的成員考慮是否提供自己的復制構(gòu)造函數(shù)

九、用類來封裝資源分配和釋放

        為什么要使用類來封裝資源分配和釋放?  
                為了防止內(nèi)存泄露。因為在函數(shù)中發(fā)生異常,那么對于動態(tài)分配的資源,就不會自動釋放,必須要手動顯式釋放,否則就會內(nèi)存泄露。而對于類對象,會自動調(diào)用其析構(gòu)函數(shù)。如果我們在析構(gòu)函數(shù)中顯式delete這些資源,就能保證這些動態(tài)分配的資源會被釋放。

        如何編寫這樣的類?  
                將資源的分配和銷毀用類封轉(zhuǎn)起來。在析構(gòu)函數(shù)中要顯式的釋放(delete或delete[])這些資源。這樣,若用戶代碼中發(fā)生異常,當作用域結(jié)束時,會調(diào)用給該類的析構(gòu)函數(shù)釋放資源。這種技術(shù)被稱為:資源分配即初始化。(resource allocation is initialization,縮寫為"RAII")。

十、auto_ptr的使用(非常重要)

        “用類封裝資源的分配和釋放”是如此的重要,C++標準庫為我們提供了一個模板類來實現(xiàn)這個功能。名稱為auto_ptr,在memory頭文件中。

        auto_ptr類的成員如下:(摘自《C++ Primer》) 

函數(shù)

功能

auto_ptr <T> ap() 默認構(gòu)造函數(shù),創(chuàng)建名為ap的未綁定的auto_ptr對象
auto_ptr<T> ap(p); 創(chuàng)建名為 ap 的 auto_ptr 對象,ap 擁有指針 p 指向的對象。該構(gòu)造函數(shù)為 explicit
auto_ptr<T> ap1(ap2); 創(chuàng)建名為 ap1 的 auto_ptr 對象,ap1 保存原來存儲在 ap2 中的指針。將所有權(quán)轉(zhuǎn)給 ap1,ap2 成為未綁定的 auto_ptr 對象
ap1 = ap2 將所有權(quán) ap2 轉(zhuǎn)給 ap1。刪除 ap1 指向的對象并且使 ap1 指向 ap2 指向的對象,使 ap2 成為未綁定
~ap 析構(gòu)函數(shù)。刪除 ap 指向的對象
*ap 返回對 ap 所綁定的對象的引用
ap-> 返回 ap 保存的指針
ap.reset(p) 如果 p 與 ap 的值不同,則刪除 ap 指向的對象并且將 ap 綁定到 p
ap.release() 返回 ap 所保存的指針并且使 ap 成為未綁定的
ap.get() 返回 ap 保存的指針

        auto_ptr類的使用: 
                1. 用來保存一個指向?qū)ο箢愋偷?strong>指針。注意必須是動態(tài)分配的對象(即使用new非配的)的指針。既不能是動態(tài)分配的數(shù)組(使用new [])指針,也不能是非動態(tài)分配的對象指針。 
                2. 慣用的初始化方法:在用戶代碼中,使用new表達式作為auto_ptr構(gòu)造函數(shù)的參數(shù)。(注意:auto_ptr類接受指針參數(shù)的構(gòu)造函數(shù)為explicit,所以必須顯式的進行初始化)。 
                3. auto_ptr的行為特征:類似普通指針行為。auto_ptr存在的主要原因就是,為了防止動態(tài)分配的對象指針造成的內(nèi)存泄露,既然是指針,其具有"*"操作符和"->"操作符。所以auto_ptr的主要目的就是:首先保證自動刪除auto_ptr所引用的對象,并且要支持普通指針行為。 
                4. auto_ptr對象的復制和賦值是有破壞性的。① 會導致右操作數(shù)成為未綁定的,導致auto_ptr對象不能放到容器中;② 在賦值的時候,將有操作符修改為未綁定,即修改了右操作數(shù),所以要保證這里的賦值操作符右操作數(shù)是可以修改的左值(然而普通的賦值操作符中,右操作數(shù)可以不是左值);③和普通的賦值操作符一樣,如果是自我賦值,那么沒有效果;④ 導致auto_ptr對象不能放到容器中。 
                5. 如果auto_ptr初始化的時候,使用默認構(gòu)造函數(shù),成為未綁定的auto_ptr對象,那么可以通過reset操作將其綁定到一個對象。 
                6. 如果希望測試auto_ptr是否已經(jīng)綁定到了一個對象,那么使用get()函數(shù)的返回值與NULL進行比較。

       auto_ptr的缺陷 
                1. 不能使用auto_ptr對象保存指向靜態(tài)分配的對象的指針,也不能保存指向動態(tài)分配的數(shù)組的指針。 
                2. 不能講兩個auto_ptr對象指向同一個對象。因為在一個auto_ptr對象析構(gòu)以后,造成另一個auto_ptr對象指向了已經(jīng)釋放的內(nèi)存。造成這種情況的兩種主要常見原因是:① 用同一個指針初始化或者reset兩個不同的auto_ptr對象;② 使用一個auto_ptr對象的get函數(shù)返回值初始化或者reset另一個auto_ptr對象。 
                3. 不能將auto_ptr對象放到容器中。因為其復制和賦值操作具有破壞性。

十一、常見的異常處理問題

    動態(tài)內(nèi)存分配錯誤

         ① 分配動態(tài)內(nèi)存使用的是new和new[]操作符,如果他們分配內(nèi)存失敗,就會拋出bad_alloc異常,在new頭文件中,所以我們的代碼中應該捕捉這些異常。常見的代碼形式如下:

  1. try {  
  2.     //其他代碼  
  3.     ptr = new int[num_max];  
  4.     //其他代碼  
  5. catch(bad_alloc &e) {  
  6.     //這里常見的處理方式為:先釋放已經(jīng)分配的內(nèi)存,然后結(jié)束程序,或者打印一條錯誤信息并繼續(xù)執(zhí)行  
  7. }  

         ② 可以使用類似C語言的方式處理,但這時要使用的nothrow版本,使用"new (nothrow)"的形式分配內(nèi)存。這時,如果分配不成功,返回的是NULL指針,而不再是拋出bad_alloc異常。 
         ③ 可以定制內(nèi)存分配失敗行為。C++允許指定一個new 處理程序(newhandler)回調(diào)函數(shù)。默認的并沒有new 處理程序,如果我們設置了new 處理程序,那么當new和new[] 分配內(nèi)存失敗時,會調(diào)用我們設定的new 處理程序,而不是直接拋出異常。通過set_new_handler函數(shù)來設置該回調(diào)函數(shù)。要求被回調(diào)的函數(shù)沒有返回值,也沒有形式參數(shù)

十二、來自C++之父Bjarne Stroustrup的建議

    節(jié)選自《The C++ Programming Language》 ——C++之父Bjarne Stroustrup 
         1. Don’t use exceptions where more local control structures will suffice;    當局部的控制能夠處理時,不要使用異常; 
         2. Use the "resource allocation is initialization" technique to manage resources;   使用“資源分配即初始化”技術(shù)去管理資源; 
         3. Minimize the use of try-blocks. Use "resource acquisition is initialization" instead of explicit handler code;    盡量少用try-catch語句塊,而是使用“資源分配即初始化”技術(shù)。 
         4. Throw an exception to indicate failure in a constructor;     如果構(gòu)造函數(shù)內(nèi)發(fā)生錯誤,通過拋出異常來指明。 
         5. 
Avoid throwing exceptions from destructors;     避免在析構(gòu)函數(shù)中拋出異常。 
         6. 
Keep ordinary code and error-handling code separate;      保持普通程序代碼和異常處理代碼分開。 
         7. Beware of memory leaks caused by memory allocated by new not being released in case of an exception;  小心通過new分配的內(nèi)存在發(fā)生異常時,可能造成內(nèi)存泄露。 
         8. 
Assume that every exception that can be thrown by a function will be thrown;    如果一個函數(shù)可能拋出某種異常,那么我們調(diào)用它時,就要假定它一定會拋出該異常,即要進行處理。 
         9. Don't assume that every exception is derived from class exception;     要記住,不是所有的異常都繼承自exception類。 
         10. A library shouldn't unilaterally terminate a program. Instead, throw an exception and let a caller decide;    編寫的供別人調(diào)用的程序庫,不應該結(jié)束程序,而應該通過拋出異常,讓調(diào)用者決定如何處理(因為調(diào)用者必須要處理拋出的異常)。 
         11. Develop an error-handling strategy early in a design;    若開發(fā)一個項目,那么在設計階段就要確定“錯誤處理的策略”。  

本文轉(zhuǎn)自:http://m.shnenglu.com/jialisoft/archive/2012/10/20/193558.html

posted on 2012-10-22 17:30 王海光 閱讀(578) 評論(0)  編輯 收藏 引用 所屬分類: C++
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            蜜桃久久av一区| 日韩一区二区免费高清| 久久国产精品久久久久久久久久| 狠狠色丁香久久婷婷综合丁香 | 欧美大片免费| 另类春色校园亚洲| 亚洲婷婷在线| 在线亚洲+欧美+日本专区| 亚洲精品字幕| 99精品欧美一区| 一本色道婷婷久久欧美| 在线亚洲精品| 午夜精品剧场| 久久激情视频久久| 老色鬼久久亚洲一区二区| 美女露胸一区二区三区| 欧美大片91| 日韩午夜黄色| 午夜宅男久久久| 久久午夜激情| 欧美一二三视频| 午夜在线不卡| 噜噜噜躁狠狠躁狠狠精品视频| 久久婷婷久久| 亚洲欧美成人| 亚洲视频在线观看| 亚洲一区欧美二区| 日韩视频在线播放| 亚洲黄色有码视频| 一区二区欧美精品| 亚洲福利视频专区| 中文在线不卡| 亚洲一区二区三区在线观看视频| 99精品国产在热久久下载| 欧美一区二区三区免费在线看| 久久久水蜜桃av免费网站| 亚洲国产电影| 9l国产精品久久久久麻豆| 欧美亚洲免费| 欧美国产日韩在线| 国产欧美日韩另类视频免费观看| 黄色日韩精品| 亚洲综合精品四区| 欧美激情国产日韩| 午夜精品一区二区三区在线播放 | 亚洲精品国产精品乱码不99| 亚洲欧美另类国产| 欧美成人dvd在线视频| 欧美国产第一页| 亚洲一区二区动漫| 欧美激情一区二区| 韩国美女久久| 午夜国产精品影院在线观看| 欧美国产精品久久| 欧美在线3区| 国产精品一区免费在线观看| 国产精品丝袜xxxxxxx| 亚洲免费av电影| 免费不卡在线观看| 欧美一区国产一区| 国产精品综合| 亚洲制服av| 日韩一级黄色av| 欧美a级一区| 亚洲国产精品精华液网站| 久久久无码精品亚洲日韩按摩| 亚洲影音先锋| 国产麻豆精品视频| 欧美在线播放| 欧美一区二区女人| 激情综合激情| 欧美成人精品在线| 免费成人在线视频网站| 午夜精品久久久久久久99热浪潮| 在线欧美电影| 久色成人在线| 噜噜噜在线观看免费视频日韩| 伊人久久av导航| 免费观看成人| 美国十次成人| 99re66热这里只有精品3直播| 亚洲福利在线视频| 欧美精品在线观看一区二区| 一区二区成人精品| 一区二区成人精品| 国产欧美日韩亚洲一区二区三区| 性伦欧美刺激片在线观看| 香蕉成人伊视频在线观看| 国产日韩av在线播放| 亚洲国产欧美不卡在线观看| 夜夜爽www精品| 亚洲另类一区二区| 欧美精品一卡| 一个色综合av| 欧美黑人一区二区三区| 一区二区三区欧美在线| 欧美三区在线| 亚洲综合欧美日韩| 亚洲一区二区网站| 欧美理论电影在线观看| 一本色道久久综合狠狠躁篇怎么玩| 亚洲国产高清一区二区三区| 欧美高清视频在线| 亚洲人成网站在线观看播放| 欧美激情视频一区二区三区在线播放 | 一道本一区二区| 欧美日韩日日骚| 一区二区三区视频在线观看| 女同一区二区| 国产精品视频网| 久久久视频精品| 麻豆免费精品视频| 亚洲毛片在线| 亚洲欧美日韩在线播放| 国产视频亚洲| 欧美v日韩v国产v| 免费观看久久久4p| 一区二区三区 在线观看视| 亚洲午夜激情| 在线精品国产欧美| 一区二区三区 在线观看视频| 国产农村妇女毛片精品久久莱园子| 久久精品日产第一区二区三区| 久久久久久久一区二区| 一区二区激情视频| 久久人人爽人人爽| 亚洲国产精品va在线观看黑人| 亚洲欧美大片| 国产一区二区三区成人欧美日韩在线观看 | 狠狠爱www人成狠狠爱综合网| 久久久精品五月天| 欧美精品一区三区在线观看| 午夜在线观看免费一区| 亚洲一区二区三区四区五区午夜| 亚洲欧洲中文日韩久久av乱码| 日韩亚洲成人av在线| 狠狠色狠狠色综合系列| 亚洲日本成人网| 一色屋精品亚洲香蕉网站| 99视频有精品| 亚洲日韩视频| 久久精品国产免费观看| 久久riav二区三区| 欧美日韩激情小视频| 久久综合一区二区三区| 国产精品久久77777| 亚洲国产成人av在线| 国产在线精品成人一区二区三区| 亚洲精品国产欧美| 亚洲大胆av| 久久精品99久久香蕉国产色戒| 亚洲视频国产视频| 欧美激情一区二区久久久| 欧美成人午夜激情| 在线观看福利一区| 午夜久久美女| 性色av香蕉一区二区| 欧美三日本三级三级在线播放| 亚洲免费观看| 艳女tv在线观看国产一区| 亚洲伊人观看| 欧美一区二区在线播放| 国产精品―色哟哟| 亚洲一区国产视频| 午夜精品久久久久久久蜜桃app| 欧美日本视频在线| 一区二区三区视频观看| 亚洲自拍偷拍麻豆| 国产精品萝li| 亚洲午夜一区| 香港久久久电影| 国产精品久久久一区二区三区| 欧美激情第一页xxx| 亚洲精品久久久久久下一站| 久久综合国产精品| 欧美成人精品一区| 日韩网站在线观看| 欧美日韩一区二区在线| 99视频在线精品国自产拍免费观看 | 国产精品v片在线观看不卡| 亚洲精品日韩精品| 一区二区三区四区在线| 欧美视频一区二区三区在线观看| 亚洲精品小视频| 亚洲一区二区三区777| 欧美成人黄色小视频| 男同欧美伦乱| 亚洲一级影院| 久久久久久久国产| 久久久91精品国产| 欧美激情精品久久久久久大尺度| 亚洲人精品午夜在线观看| 欧美日韩国产一中文字不卡| 亚洲免费在线看| 欧美1区3d| 亚洲视频一区| 国产一区再线| 国产精品免费一区二区三区观看| 亚洲摸下面视频| 免费一级欧美在线大片|