• <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>

            拂曉·明月·彎刀

            觀望,等待只能讓出現(xiàn)的機會白白溜走

              C++博客 :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理 ::
            轉(zhuǎn)自:http://msdn.microsoft.com/zh-cn/library/ms809695.aspx#mainSection

            發(fā)布日期 : 9/9/2004 | 更新日期 : 9/9/2004

            Jon Pincus
            Microsoft Corporation

            摘要:討論錯誤處理范例以及與多個范例相關(guān)聯(lián)的陷阱,并提供了兩個簡單但至關(guān)重要的有關(guān)錯誤情況處理的原則。

            本頁內(nèi)容

            簡介 簡介 
            錯誤處理范例 錯誤處理范例 
            多個 API 約定的問題 多個 API 約定的問題 
            有關(guān)錯誤情況的兩個簡單原則 有關(guān)錯誤情況的兩個簡單原則 
            小結(jié) 小結(jié) 

            簡介

            有能力的程序員能夠編寫在未發(fā)生異常情況時正常運行的代碼。使程序員出類拔萃的技能之一是能夠編寫在發(fā)生錯誤和出現(xiàn)“意外事件”時仍然能繼續(xù)運行的代碼。然而,術(shù)語“意外事件”會給人一種錯誤的印象。如果您的代碼嵌入在一個廣泛分布的成功產(chǎn)品中,那么您應(yīng)該預(yù)料到代碼可能發(fā)生的各種異常(且可怕)的情況。計算機將耗盡內(nèi)存,文件未如您所愿地存在于應(yīng)該存在的地方,從未失敗的函數(shù)有可能在新版本的操作系統(tǒng)中失敗,等等,不一而足。如果您希望代碼能繼續(xù)可靠地運行,那么就需要預(yù)見所有這些事件。

            本文討論的特定類別的異常事件是錯誤情況。錯誤情況并沒有一個準(zhǔn)確的定義。直觀地講,它就是指通常能夠成功的事情并未成功。內(nèi)存分配失敗就是一個典型示例。通常,系統(tǒng)有大量內(nèi)存可以滿足需求,但是偶爾計算機也可能會由于某種原因而特別繁忙,例如,運行大型的電子表格計算,或者在 Internet 世界中有人正在對該計算機發(fā)動拒絕服務(wù)攻擊。如果您要編寫任意類型的重要組件、服務(wù)或應(yīng)用程序,那么就需要預(yù)見到這種情況。

            本文采用的編碼示例基于 C/C++,但一般原則是獨立于編程語言的。即使不使用 C/C++ 代碼,使用多種語言的程序員也應(yīng)該記住這一點。例如,PC Week 舉辦的黑客競賽 (Hackpcweek.com) 的獲勝者,就是利用某些 Perl CGI 代碼中檢查返回代碼的失敗,來部分地對 Apache 服務(wù)器發(fā)起攻擊。有關(guān)進一步的信息,請參閱 http://www.zdnet.com/eweek/stories/general/0,11011,2350744,00.html 上的文章。

            任何重要的軟件部分都會與其他的層和組件進行交互。編寫處理錯誤的代碼的第一步,是了解當(dāng)錯誤發(fā)生時系統(tǒng)的其余部分正在執(zhí)行哪些操作。本文的其余部分將討論錯誤處理范例,然后討論與多個范例相關(guān)聯(lián)的陷阱。本文還包括了兩個簡單但至關(guān)重要的有關(guān)錯誤情況處理的原則。

            錯誤處理范例

            無論何時發(fā)生錯誤情況,都需要考慮三個獨立的問題:檢測錯誤情況、報告錯誤情況以及對錯誤情況作出響應(yīng)。通常,處理這些問題的職責(zé)分散在代碼的不同組件或?qū)又小@纾瑱z測系統(tǒng)是否內(nèi)存不足是操作系統(tǒng)的工作。內(nèi)存分配函數(shù)的工作是將這種情況報告給它的調(diào)用方。例如,VirtualAlloc 會返回 NULL,Microsoft 基礎(chǔ)類庫 (MFC) 運算符new 會引發(fā)CMemoryException *,而 HeapAlloc 可能會返回 NULL 或引發(fā)結(jié)構(gòu)化異常。調(diào)用方的工作就是對此作出響應(yīng),方法是清理自身的工作,捕捉異常,并且還可能將失敗報告給它的調(diào)用方或用戶。

            因為不同的層和組件需要相互協(xié)作以處理這些錯誤,所以第一步是定義特殊詞匯,即,所有組件共同遵守的約定。遺憾的是,在 C、C++ 或其他任何語言中都沒有單一且定義完善的約定。相反,卻存在許多約定,并且每種約定都有各自的優(yōu)缺點。

            下面列出了一些最常用的約定:

            • 返回一個 BOOL 值以指示成功或失敗。Windows API 和 MFC 中的很多調(diào)用都返回 TRUE 以指示成功,返回 FALSE 以指示失敗。這種方法既好又簡單。但問題在于,該方法不對失敗進行解釋,也不區(qū)分不同類型的成功或失敗。(當(dāng)使用 Windows API 時,您可以使用 GetLastError 來獲得特定代碼。)

            • 返回狀態(tài)。遺憾的是,隨著 Windows API 的變化,該約定出現(xiàn)了兩種不同的樣式。COM 函數(shù)返回 HRESULT:HRESULT >= 0(例如,S_OK)表示成功,HRESULT < 0(例如,E_FAIL)表示失敗。其他函數(shù)(例如,Registry 函數(shù))則返回 WINERROR.H 中定義的錯誤代碼。在該約定中,ERROR_SUCCESS (0) 是唯一的成功值,所有其他值都表示各種形式的失敗。這種不一致有可能造成各種各樣的混亂。更糟糕的是,值 0(它在 Boolean 樣式的返回值約定中表示失敗)在此處表示成功。其后果將在后面進行討論。在任何事件中,狀態(tài)返回方法都具有優(yōu)勢 — 不同的值可以表示不同類型的失敗(或者對于 HRESULT 而言,表示成功)。

            • 返回一個 NULL 指針。C 樣式內(nèi)存分配函數(shù)(例如,HeapAllocVirtualAllocGlobalAlloc  malloc)通常返回一個 NULL 指針。另一個示例是 C 標(biāo)準(zhǔn)庫的 fopen 函數(shù)。與 BOOL 返回值相同,還需要其他一些機制來區(qū)分不同種類的失敗。

            • 返回一個  不可能的值  該值通常為 0(對于整數(shù),如 GetWindowsDirectory)或 –1(對于指針或長度,如 C 標(biāo)準(zhǔn)庫的 fgets 函數(shù))。NULL 指針約定的泛化是它找到某個值 — 例程采用其他方式將無法返回該值,并且讓該值表示錯誤。因為通常沒有中心模式,所以在將該方法擴展到大型 API 時會在某種程度上出現(xiàn)問題。

            • 引發(fā) C++ 異常。對于純粹的 C++ 程序來說,該約定可讓您使用語言功能來獲益。Bobby Schmidt 最近撰寫的有關(guān)異常的“Deep C++”系列文章詳細(xì)討論了這些問題。然而,將該方法與舊式的 C 代碼或者與 COM 結(jié)合可能會帶來問題。對于 COM 方法而言,引發(fā) C++ 異常是非法的。此外,C++ 異常是開銷相對較大的一種機制。如果操作本身的價值不高,那么過大的開銷通常會抵消所獲得的好處。

            • 引發(fā)結(jié)構(gòu)化異常。這里的注意事項恰與 C++ 異常相反。該方法對于 C 代碼而言非常整潔,但與 C++ 的交互性不太好。同樣,該方法不能與 COM 有效地結(jié)合。

             如果您要選用較舊的代碼基,那么您有時會看到“原生的異常處理機制”。C++ 編譯器只是在最近才開始比較好地處理異常。在過去,開發(fā)人員經(jīng)常基于 Windows 結(jié)構(gòu)化異常處理 (SEH) 或 C 庫的 setjmp/longjmp 機制來構(gòu)建他們自己的機制。如果您已經(jīng)繼承了這些代碼基中的一個,則需要自擔(dān)風(fēng)險,重新編寫它可能是最好的選擇。否則,最好由經(jīng)驗非常豐富的程序員來處理。

            錯誤處理是任何 API 定義的關(guān)鍵部分。無論您是要設(shè)計 API 還是使用他人設(shè)計的 API,都是如此。對于 API 定義而言,錯誤行為范例與類定義或命名方案同樣重要。例如,MFC API 非常明確地規(guī)定了在資源分配失敗時哪些函數(shù)引發(fā)哪些異常,以及哪些函數(shù)返回 BOOL 成功/失敗調(diào)用。API 的設(shè)計者明確地將某些想法植入這一規(guī)定,用戶需要理解其意圖并按照已經(jīng)構(gòu)建的規(guī)則進行操作。

            如果您要使用現(xiàn)有的 API,則必須處理所有現(xiàn)有約定。如果您要設(shè)計 API,則應(yīng)該選用能夠與您已經(jīng)使用的 API 相適應(yīng)的約定。

            如果您要使用多個 API,則通常要使用多個約定。某些約定組合可以很好地工作,因為這些約定很難混淆。但是,某些約定組合卻很容易出錯。本文所討論的許多特定陷阱就是由于存在這些不一致而造成的。

            多個 API 約定的問題

            混用和匹配不同的 API 約定通常是無法避免的,但這非常容易出錯。一些實例是顯而易見的。例如,如果您嘗試在同一個可執(zhí)行文件中混用 Windows SEH 和 C++ 異常,則很可能會失敗。其他示例更為微妙。其中一個反復(fù)出現(xiàn)的特定示例就與 HRESULT 有關(guān),并且是以下示例的某種變體:

            extern BOOL DoIt();
            BOOL ok;
            ok = DoIt(...);
            if (FAILED(ok))     // WRONG!!!
            return;
            

            該示例為何是錯誤的?FAILED 是一個 HRESULT 樣式的宏,因此它會檢查其參數(shù)是否小于 0。以下是它的定義(摘自 winerror.h):

            #define FAILED(Status) ((HRESULT)(Status)<0)
            

            因為 FALSE 被定義為 0,所以 FAILED(FALSE) == 0 是違反直覺的,這無須多言。而且,因為該定義嵌入了強制轉(zhuǎn)換,所以即使您使用警告級別 4,也不會獲得編譯器警告。

            當(dāng)您處理 BOOL 時,不應(yīng)該使用宏,但應(yīng)該進行顯式檢查:

            BOOL ok;
            ok = DoIt(...);
            if (! ok)
            return;
            

            相反,當(dāng)您處理 HRESULT 時,則應(yīng)該始終使用 SUCCEEDED 和 FAILED 宏。

            HRESULT hr;
            hr = ISomething->DoIt(...);
            if (! hr)     // WRONG!!!
            return;
            

            這是一個惡性錯誤,因為它很容易被忽略。如果 CoDoIt 返回 S_OK,則測試將成功完成。但是,如果 CoDoIt 返回某個其他成功狀態(tài),會怎樣呢?那樣,hr > 0,所以 !hr == 0;if 測試失敗,代碼將返回實際上并未發(fā)生的錯誤。

            下面是另一個示例:

            HRESULT hr;
            hr = ISomething->DoIt(...);
            if (hr == S_OK)     // STILL WRONG!!!
            return;
            

            人們有時會插話說 ISomething::DoIt 在成功時總是返回 S_OK,因此最后兩個代碼片段肯定都沒有問題。但是,這不是一個安全的假設(shè)。COM 接口的說明非常清楚。函數(shù)在成功時可以返回任何成功值,因此 ISomething::DoIt 的眾多實現(xiàn)者中的任何一個都可能選擇返回某個值,例如 S_FALSE。在這種情況下,您的代碼將中止運行。

            正確的解決方案是使用宏,這也就是宏存在的原因。

            HRESULT hr;
            hr = ISomething->DoIt(...);
            if (FAILED(hr))
            return;
            

            因為已經(jīng)引出了 HRESULT 的主題,所以現(xiàn)在是提醒您 S_FALSE 特性的大好時機:

            • 它是一個成功代碼,而不是一個失敗代碼,因此 SUCCEEDED(S_FALSE) == 1。

            • 它被定義為 1,而不是 0,因此 S_FALSE == TRUE。

            有關(guān)錯誤情況的兩個簡單原則

            有許多簡單的方法可以使代碼更可靠地處理錯誤情況。相反,人們不愿意做的許多簡單事情會使代碼在發(fā)生錯誤情況時變得脆弱和不可靠。

            總是檢查返回狀態(tài)

            沒有比這更簡單的事情了。幾乎所有函數(shù)都提供某種表明它們是成功還是失敗的指示,但如果您不檢查它們,則這一點沒有任何用處。這能有多困難呢?可以將其視為一個衛(wèi)生問題。您知道在吃東西之前應(yīng)該洗手,但您可能并不總是這樣做。這與檢查返回值的道理相同。

            下面是一個涉及到 GetWindowsDirectory 函數(shù)的簡單而實用的示例。MSDN 文檔清楚地說明了 GetWindowsDirectory 的錯誤行為:

            Return Values
            

            如果該函數(shù)失敗,則返回值為 0。要獲得擴展的錯誤信息,請調(diào)用 GetLastError 函數(shù)。

            實際上,文檔中寫得非常清楚。

            下面是一個判斷 Windows 目錄駐留在哪個驅(qū)動器中的代碼片段。

            TCHAR cDriveLetter;
            TCHAR szWindowsDir[MAX_PATH];
            GetWindowsDirectory(szWindowsDir, MAX_PATH);
            cDriveLetter = szWindowsDir[0];   // WRONG!!!
            ...
            

            如果 GetWindowsDirectory 失敗,會發(fā)生什么情況呢?(如果您不相信 GetWindowsDirectory 會失敗,這只是您暫時的觀點。)好,該代碼不檢查返回值,因此分配給 cDriveLetter 的值未初始化。未初始化的內(nèi)存可以具有任意值。實際上,該代碼將隨機選擇驅(qū)動器。這樣做幾乎不可能是正確的。

            正確的做法是檢查錯誤狀態(tài)。

            TCHAR cDriveLetter;
            TCHAR szWindowsDir[MAX_PATH];
            if (GetWindowsDirectory(szWindowsDir, MAX_PATH))
            {
            cDriveLetter = szWindowsDir[0];
            ...
            }
            

            這種情況還能發(fā)生嗎?不檢查返回值的最常見借口是“我知道那個函數(shù)絕對不會失敗”。GetWindowsDirectory 就是一個很好的示例。一直到 Windows® 98 和 Windows NT® 4.0,它實際上確實沒有失敗過,因此許多人養(yǎng)成了一個不好的習(xí)慣,即,假設(shè)它永遠(yuǎn)不會失敗。

            現(xiàn)在 Windows 終端服務(wù)器出現(xiàn)了,要判斷單個用戶的 Windows 目錄變得更為復(fù)雜。GetWindowsDirectory 必須完成更多的工作,可能包括分配內(nèi)存。而且,因為開發(fā)這一函數(shù)的開發(fā)人員非常負(fù)責(zé)任,所以他完成了正確的工作并檢查內(nèi)存分配是否成功,如果不成功,則返回描述完整的錯誤狀態(tài)。

            這就導(dǎo)致了另外一些問題:如果 GetWindowsDirectory 在失敗時已經(jīng)將它的輸出初始化為空字符串,是否會有所幫助?答案是否定的。結(jié)果不會是未初始化的,但它們?nèi)詫⑹谴中拇笠獾膽?yīng)用程序所未曾料到的東西。假設(shè)您具有一個由 cDriveLetter – 'A' ; 索引的數(shù)組,那么現(xiàn)在該索引將突然變?yōu)樨?fù)值。

            即使終端服務(wù)器對于您不是問題,但同樣的情況可能會發(fā)生在 Windows API 的任何未來實現(xiàn)中。您希望禁止正在開發(fā)的應(yīng)用程序在將來版本的操作系統(tǒng)或替代實現(xiàn)(如 Embedded NT)中運行嗎?一種良好的習(xí)慣是記住以下事實:代碼經(jīng)常在其預(yù)期的到期日之后繼續(xù)生存。

            有時,檢查返回值是不夠的。請考慮 Windows API ReadFile。您經(jīng)常會看到如下代碼:

            LONG buffer[CHUNK_SIZE];
            ReadFile(hFile, (LPVOID)buffer,
            CHUNK_SIZE*sizeof(LONG), &cbRead, NULL);
            if (buffer[0] == 0)   // DOUBLY WRONG!!!
            ...
            

            如果讀取操作失敗,說明緩沖區(qū)的內(nèi)容是未初始化的。多數(shù)情況下它可能為零,但這一點并不確定。

            讀取文件失敗的原因有許多。例如,該文件可能是遠(yuǎn)程文件,而網(wǎng)絡(luò)可能發(fā)生故障。即使它是本地文件,磁盤也可能恰好不合時宜地?fù)p壞。如果是這種情況,則文件的格式可能完全不同于預(yù)期格式。他人可能無意中或別有用心地替換了您認(rèn)為應(yīng)該存在于某個位置的文件,或者該文件可能只有一個字節(jié)。更為奇怪的事情已經(jīng)發(fā)生了。

            要處理這一情況,您不但需要檢查讀取操作是否成功,還必須檢查以確保您已經(jīng)讀取了正確數(shù)量的字節(jié)。

            LONG buffer[CHUNK_SIZE];
            BOOL ok;
            ok = ReadFile(hFile, (LPVOID)buffer,
            CHUNK_SIZE*sizeof(LONG), &cbRead, NULL);
            if (ok && cbRead > sizeof(LONG)) {
            if (buffer[0] == 0)
            ...
            }
            else
            // handle the read failure; for example
            ...
            

            無庸諱言,上述代碼有點兒復(fù)雜。但是,編寫可靠的代碼要比編寫并不總是能夠正常工作的代碼更為復(fù)雜。對上述代碼產(chǎn)生性能方面的疑問是很正常的。雖然添加了幾個測試,但在全局上下文(函數(shù)調(diào)用、磁盤操作,至少復(fù)制 CHUNK_SIZE * sizeof(LONG) 個字節(jié))中,其影響是極小的。

            通常,每當(dāng)需要進行返回值檢查時,總是涉及到一個函數(shù)調(diào)用,因此性能開銷不太重要。在某些情況下,編譯器可能會內(nèi)聯(lián)該函數(shù),但是如果發(fā)生這種行為,并且由于返回常數(shù)而實際上不需要檢查返回值時,編譯器會將測試優(yōu)化掉。

            誠然,還是有一些特殊情況:您通過刪除返回值檢查而節(jié)省的少數(shù) CPU 循環(huán)至關(guān)重要;編譯器無法為您提供幫助;您控制了要調(diào)用的函數(shù)的行為。在上述情況下,省略一些返回值檢查是有意義的。如果您認(rèn)為自己處于類似的情形,則應(yīng)該與其他開發(fā)人員進行討論,重新審視真正的性能折衷,然后,如果您仍然確信這樣做是正確的,則在代碼中每個省略返回值檢查的地方加上明確的注釋,說明您的決定并證明它的正確性。

            總是檢查內(nèi)存分配

            無論是使用 HeapAllocVirtualAllocIMalloc::AllocSysAllocStringGlobalAllocmalloc 還是任何 C++ 運算符 new,您都不能想當(dāng)然地認(rèn)為內(nèi)存分配成功。同樣的道理也適用于其他各種資源,包括 GDI 對象、文件、注冊表項等等。

            下面是一個很好的獨立于平臺的錯誤代碼示例,這些代碼是在 C 標(biāo)準(zhǔn)庫的基礎(chǔ)上編寫的:

            char *str;
            str = (char *)malloc(MAX_PATH);
            str[0] = 0;         // WRONG!!!
            ...
            

            在此例中,如果內(nèi)存耗盡,則 malloc 將返回 NULL,而 str 的反引用將是 NULL 指針的反引用。這會造成訪問沖突,從而導(dǎo)致程序崩潰。除非您是在內(nèi)核模式下運行(例如,設(shè)備驅(qū)動程序),否則訪問沖突將導(dǎo)致藍(lán)屏或可利用的安全漏洞。

            解決方案非常簡單。檢查返回值是否為 NULL,并執(zhí)行正確的操作。

            char *str;
            str = (char *)malloc(MAX_PATH);
            if (str != NULL)
            {
            str[0] = 0;
            ...
            }
            

            與返回值檢查一樣,許多人相信實際上不會發(fā)生內(nèi)存分配問題。誠然,該問題并不總是發(fā)生,但這并不意味著它永遠(yuǎn)不會發(fā)生。如果您讓成千上萬(或數(shù)以百萬)的用戶運行您的軟件,即使該問題每月僅對每個用戶發(fā)生一次,后果也是嚴(yán)重的。

            許多人相信,在內(nèi)存耗盡時做什么都是無所謂的。程序應(yīng)該退出。但是,這在許多方面都不適用。首先,假設(shè)程序在內(nèi)存耗盡時退出,那么將不會保存數(shù)據(jù)文件。其次,人們通常期望服務(wù)和應(yīng)用程序能夠長期運行,因此它們能夠在內(nèi)存暫時不足時繼續(xù)正常運行是至關(guān)重要的。第三,對于在嵌入式環(huán)境中運行的軟件而言,退出不是可行的選擇。處理內(nèi)存分配可能非常麻煩,但這件事情必須做。

            有時,意外的 NULL 指針可能不會導(dǎo)致程序崩潰,但這仍然不是件好事情。

            HBITMAP hBitmap;
            HBITMAP hOldBitmap;
            hBitmap = CreateBitmap(. . .);
            hOldBitmap = SelectObject(hDC, hBitmap);   // WRONG!!!
            ...
            

            SelectObject 的文檔在對 NULL 位圖執(zhí)行哪些操作方面含糊不清。這可能不會導(dǎo)致崩潰,但它顯然是不可靠的。代碼很可能出于某種原因而創(chuàng)建位圖,并希望用它來進行一些繪圖工作。但是,因為它未能創(chuàng)建位圖,所以繪圖操作將不會發(fā)生。即使代碼沒有崩潰,這里也明顯存在一個錯誤。同樣,您需要進行檢查。

            HBITMAP hBitmap;
            HBITMAP hOldBitmap;
            hBitmap = CreateBitmap(. . .);
            if (hBitmap != NULL)
            {
            hOldBitmap = SelectObject(hDC, hBitmap);
            ...
            }
            else
            ...
            

            當(dāng)您使用 C++ 運算符 new 時,事情開始變得更加有趣。例如,如果您要使用 MFC,則全局運算符 new 將在內(nèi)存耗盡時引發(fā)一個異常。這意味著您不能執(zhí)行以下操作:

            int *ptr1;
            int *ptr2;
            ptr1 = new int[10];
            ptr2 = new int[10];   // WRONG!!!!
            

            如果第二次內(nèi)存分配引發(fā)異常,則第一次分配的內(nèi)存將泄漏。如果您的代碼嵌入到將要長期運行的服務(wù)或應(yīng)用程序中,則這些泄漏會累積起來。

            只是捕捉異常是不夠的,您的異常處理代碼還必須是正確的。不要掉到下面這個誘人的陷阱中:

            int *ptr1;
            int *ptr2;
            try {
            ptr1 = new int[10];
            ptr2 = new int[10];
            }
            catch (CMemoryException *ex) {
            delete [] ptr1;   // WRONG!!!
            delete [] ptr2;    // WRONG!!!
            }
            

            如果第一次內(nèi)存分配引發(fā)了異常,您將捕捉該異常,但要刪除一個未初始化的指針。如果您足夠幸運,這將導(dǎo)致即時訪問沖突和崩潰。更有可能的是,它將導(dǎo)致堆損壞,從而造成數(shù)據(jù)損壞和/或在將來難以調(diào)試的崩潰。盡力初始化下列變量是值得的:

            int *ptr1 = 0;
            int *ptr2 = 0;
            try {
            ptr1 = new int[10];
            ptr2 = new int[10];
            }
            catch (CMemoryException *ex) {
            delete [] ptr1;
            delete [] ptr2;
            }
            

            應(yīng)該指出的是,C++ 運算符 new 有許多微妙之處。您可以用多種不同的方式來修改全局運算符 new 的行為。不同的類可以具有它們自己的運算符 new,并且如果您不使用 MFC,則可能會看到不同的默認(rèn)行為。例如,在內(nèi)存分配失敗時返回 NULL,而不是引發(fā)異常。有關(guān)該主題的詳細(xì)信息,請參閱 Bobby Schmidt 的“Deep C++”系列文章中有關(guān)處理異常的第 7 部分

            小結(jié)

            如果您要編寫可靠的代碼,則至關(guān)重要的一點是從一開始就考慮如何處理異常事件。您不能事后再考慮對異常事件的處理。在考慮此類事件時,錯誤處理是一個關(guān)鍵的方面。

            錯誤處理很難正確執(zhí)行。盡管本文只是粗淺地討論了這一問題,但其中介紹的原則奠定了一個強大的基礎(chǔ)。請記住以下要點:

            • 在設(shè)計應(yīng)用程序(或 API)時,應(yīng)預(yù)先考慮您喜歡的錯誤處理范例。

            • 在使用 API 時,應(yīng)了解它的錯誤處理范例。

            • 如果您處于存在多個錯誤處理范例的情況下,請警惕可能造成混亂的根源。

            • 總是檢查返回狀態(tài)。

            • 總是檢查內(nèi)存分配。

            如果您執(zhí)行了上述所有操作,就能夠編寫出可靠的應(yīng)用程序。

            posted on 2011-04-19 23:40 一路風(fēng)塵 閱讀(321) 評論(0)  編輯 收藏 引用 所屬分類: 轉(zhuǎn)載
            亚洲国产成人精品91久久久| 99久久99久久精品国产| 久久强奷乱码老熟女网站| 亚洲欧洲日产国码无码久久99| 久久国产精品一区二区| 亚洲精品久久久www| 久久婷婷五月综合色奶水99啪| 中文字幕成人精品久久不卡 | 伊人色综合九久久天天蜜桃| 久久久久久久久久久| 91久久香蕉国产熟女线看| 久久久久se色偷偷亚洲精品av| 99久久精品免费看国产| 蜜臀久久99精品久久久久久小说 | 无码AV中文字幕久久专区| 国产精品xxxx国产喷水亚洲国产精品无码久久一区 | 一本色道久久88综合日韩精品 | 久久www免费人成看国产片| 久久久久这里只有精品| 久久久久人妻精品一区二区三区| 久久天堂电影网| 久久夜色精品国产噜噜噜亚洲AV| 久久久久国产| 国产精品伦理久久久久久| 国产午夜精品久久久久免费视| 久久久久亚洲AV片无码下载蜜桃| 久久不见久久见免费影院www日本| 99久久成人国产精品免费| 久久久久人妻一区精品性色av| 亚洲国产精品成人久久| 精品久久久无码人妻中文字幕| 四虎影视久久久免费| 久久精品国产亚洲av瑜伽| 激情综合色综合久久综合| 国产一区二区精品久久凹凸| 国产免费久久久久久无码| 91性高湖久久久久| 久久天天日天天操综合伊人av| 久久精品国产亚洲Aⅴ香蕉 | 国产成人精品三上悠亚久久| 久久精品aⅴ无码中文字字幕不卡|