C++異常處理assert,throw,exit用法


常見的幾個小細節問題。

  • assert應用:

      在現實世界中,我們腦袋時刻都在判斷對與錯,對的事情我們會繼續深入下去,而錯的事情我們會馬上停止,那么在編程開發中我們如何賦予程序這種判斷事物對錯的能力呢?其中一個方案就可以使用斷言assert,我們最常用的地方就是在函數中檢查形參的數據合法性。

1、函數所屬頭文件:

        assert.h

2、函數原型:

        void assert (int expression);

3、功能說明:

        assert的關鍵在於判斷expression的邏輯真假,如果為false,就會在stderr上面打印一條包含“表達式,文件名,行號”的錯誤信息,然后調用abort結束整個程序。

4、程序實例:

#include <stdio.h>
#include <stdlib.h>
//#define NDEBUG        //可以禁止斷言
#include <assert.h>

void main()
{
    //測試true情況:以寫打開一個文件,不存在則創建新文件
    FILE *fpWrite = fopen("d:\\testWrite", "w");

    //不會出錯
    assert(fpWrite != NULL);

    fclose(fpWrite);

    //測試false情況:以讀打開一個文件,不存在會失敗
    FILE *fpRead = fopen("d:\\testRead", "r");

    //會出錯
    assert(fpRead != NULL);

    //程序調用abort退出,不會執行到此步
    fclose(fpRead);
    system("pause");
}

結果:

    當然,頻繁的調用assert會影響系統性能,增加系統額外的開銷,如果想禁用斷言功能時,可以在assert.h頭文件之前定義NDEBUG。

 

  • throw應用:

出錯是時可以用throw,然后在catch里面處理,
asert只是一個debug的檢查,檢查條件的真假,在release下asert語句不會被調用。

    拋出異常(也稱為拋棄異常)即檢測是否產生異常,在C++中,其采用throw語句來實現,如果檢測到產生異常,則拋出異常。該語句的格式為:
throw 表達式;
    如果在try語句塊的程序段中(包括在其中調用的函數)發現了異常,且拋棄了該異常,則這個異常就可以被try語句塊后的某個catch語句所捕獲並處理,捕獲和處理的條件是被拋棄的異常的類型與catch語句的異常類型相匹配。由於C++使用數據類型來區分不同的異常,因此在判斷異常時,throw語句中的表達式的值就沒有實際意義,而表達式的類型就特別重要。

    eg:除數為0的異常可以用try/catch語句來捕獲異常,並使用throw語句來拋出異常,從而實現異常處理,實現代碼:

#include <iostream>
using namespace std;
double fuc(double x, double y)
{
    if (y == 0)
    {
        throw y;
    }
    return x / y;
}
void main()
{
    double res;
    try
    {
        res = fuc(2, 3);
        cout << "the result of x/y is" << res << endl;
        res = fuc(4, 0);
    }
    catch (double)
    {
        cerr << "error of dividing zero.\n";
        exit(1);
    }    
}

1、基礎介紹

try
{
    //程序中拋出異常
    throw value;
}
catch (valuetype v)
{
    //例外處理程序段
}

語法小結:throw拋出值,catch接受,當然,throw必須在“try語句塊”中才有效。

2、深入throw:
(i)、程序接受到throw語句后就會自動調用析構器,把該域(try后的括號內)對象clean up,然后再進
入catch語句(如果在循環體中就退出循環)。

這種機制會引起一些致命的錯誤,比如,當“類”有指針成員變量時(又是指針!),在 “類的構建器
”中的throw語句引起的退出,會導致這個指針所指向的對象沒有被析構。這里很基礎,就不深入了,提
示一下,把指針改為類就行了,比如模板類來代替指針,在模板類的內部設置一個析構函數。

(ii)、語句“throw;”拋出一個無法被捕獲的異常,即使是catch(...)也不能捕捉到,這時進入終止函數
,見下catch。

3、深入catch:
一般的catch出現的形式是:
try{}
catch(except1&){}
catch(except2&){}
catch(...){} //接受所有異常
一般都寫成引用(except1&),原因很簡單,效率。

問題a:拋出異常,但是catch不到異常怎么辦?(注意沒有java類似的finally語句
在catch沒有捕獲到匹配的異常的時候,會調用默認的終止函數。可以調用set_terminate()來設置終止函數,參數是一個函數指針,類型是:void (*terminate)()。

到這里,可以題個問題:“沒有try-catch,直接在程序中"throw;",會怎么樣?”

其他一些技巧:
4、try一個函數體,形式如下

void fun(type1,type2) try----try放在函數體后
{
   函數定義
}
catch(typeX){}
這個用法的效果就相當於:
void fun() 
{
   try{函數定義}
}

5、throw一個函數體,形式如下:

void fun (); // 能拋出任何類型的異常
void fun () throw(except1,except2,except3) 
               // 后面括號里面是一個異常參數表,本例中只能拋出這3中異常
void fun () throw()   // 參數表為空,不能拋出異常

問題b:假設fun()中拋出了一個不在“異常參數表”中的異常,會怎么樣?

答:調用set_terminate()中設定的終止函數。然而,這只是表面現象,實際上是調用默認的unexpected()函數,然而這個默認的unexpected()調用了set_terminate()中設定的終止函數。可以用set_unexpected()來設置 unexpected,就像set_terminate()一樣的用法,但是在設定了新的“unexpected()”之后,就不會再調用 set_terminater中設定的終止函數了。

這個語法是很有用的,因為在用別人的代碼時,不知道哪個地方會調用什么函數又會拋出什么異常,用一個異常參數表在申明時限制一下,很實用。

  • exit()應用:

函數: exit()

函數名: exit()
所在頭文件:stdlib.h(如果是”VC6.0“的話頭文件為:windows.h)
功 能: 關閉所有文件,終止正在執行的進程。
exit(1)表示異常退出.這個1是返回給操作系統的。
exit(x)(x不為0)都表示異常退出;
exit(0)表示正常退出。
exit()的參數會被傳遞給一些操作系統,包括UNIX,Linux,和MS DOS,以供其他程序使用。
stdlib.h: void exit(int status);
參 數 : status //程序退出的返回值
 
exit()和return的區別:
按照ANSI C,在最初調用的main()中使用return和exit()的效果相同。
但要注意這里所說的是“最初調用”。如果main()在一個遞歸程序中,exit()仍然會終止程序;但return將
控制權移交給遞歸的前一級,直到最初的那一級,此時return才會終止程序。return和exit()的另一個區別
在於,即使在除main()之外的函數中調用exit(),它也將終止程序。
_exit()與exit的區別:
頭文件:
exit:#include<stdlib.h>
_exit:#include<unistd.h>
_exit()函數:直接使進程停止運行,清除其使用的內存空間,並銷毀其在內核中的各種數據結構;
exit()函數則在這些基礎上作了一些包裝,在執行退出之前加了若干道工序。
exit()函數與_exit()函數最大的區別就在於 exit()函數在調用 exit 系統調用之前要檢查文件的打開情況,把文件緩沖區中的內容寫回文件。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM