日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

c++ 使用throw抛出异常

發(fā)布時間:2025/6/15 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++ 使用throw抛出异常 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

拋出異常(也稱為拋棄異常)即檢測是否產(chǎn)生異常,在C++中,其采用throw語句來實現(xiàn),如果檢測到產(chǎn)生異常,則拋出異常。該語句的格式為:
throw 表達(dá)式;
??? 如果在try語句塊的程序段中(包括在其中調(diào)用的函數(shù))發(fā)現(xiàn)了異常,且拋棄了該異常,則這個異常就可以被try語句塊后的某個catch語句所捕獲并處理,捕獲和處理的條件是被拋棄的異常的類型與catch語句的異常類型相匹配。由于C++使用數(shù)據(jù)類型來區(qū)分不同的異常,因此在判斷異常時,throw語句中的表達(dá)式的值就沒有實際意義,而表達(dá)式的類型就特別重要。
【范例20-2】處理除數(shù)為0的異常。該范例將上述除數(shù)為0的異常可以用try/catch語句來捕獲異常,并使用throw語句來拋出異常,從而實現(xiàn)異常處理,實現(xiàn)代碼如代碼清單20-2所示。
代碼清單20-2
1??? #include<iostream.h>???????????????????????????????? //包含頭文件
2??? #include<stdlib.h>
3??? double fuc(double x, double y)??????????????????????? //定義函數(shù)
4??? {
5??????? if(y==0)
6??????? {
7??????????? throw y;??????????????????????????????????? //除數(shù)為0,拋出異常
8??????? }
9??????? return x/y;??????????????????????????????????? //否則返回兩個數(shù)的商
10??? }
11??? void main()
12??? {
13??????? double res;
14??????? try??????????????????????????????????????????? //定義異常
15??????? {
16??????????? res=fuc(2,3);
17??????????? cout<<"The result of x/y is : "<<res<<endl;
18??????????? res=fuc(4,0);??????????????????????????????? //出現(xiàn)異常
19??????? }
20??????? catch(double)??????????????????????????????????? //捕獲并處理異常
21??????? {
22??????????? cerr<<"error of dividing zero.\n";
23??????????? exit(1);??????????????????????????????????? //異常退出程序
24??????? }
25??? }
【運(yùn)行結(jié)果】在Visual C++中新建一個【C++ Source File】文件,輸入上述的代碼,編譯無誤后運(yùn)行。
【范例解析】上述代碼中,在主函數(shù)main()的第14~19行中使用了try語句定義異常,其中包含3條有可能出現(xiàn)異常的語句,它們?yōu)檎{(diào)用兩個數(shù)相除的函數(shù)。在代碼的第20~24行定義了異常處理,即捕獲異常后執(zhí)行該段代碼中的語句。此外,在函數(shù)fuc()的代碼5~8行通過throw語句拋出異常。

注意:一般來說,throw語句通常與try- catch或try-finally語句一起使用,可以使用throw語句顯式引發(fā)異常。

c++ try_catch
?
1、基礎(chǔ)介紹
try
{
//程序中拋出異常
throw value;
}
catch(valuetype v)
{
//例外處理程序段
}
語法小結(jié):throw拋出值,catch接受,當(dāng)然,throw必須在“try語句塊”中才有效。

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

這種機(jī)制會引起一些致命的錯誤,比如,當(dāng)“類”有指針成員變量時(又是指針!),在 “類的構(gòu)建器
”中的throw語句引起的退出,會導(dǎo)致這個指針?biāo)赶虻膶ο鬀]有被析構(gòu)。這里很基礎(chǔ),就不深入了,提
示一下,把指針改為類就行了,比如模板類來代替指針,在模板類的內(nèi)部設(shè)置一個析構(gòu)函數(shù)。

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

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

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

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


其他一些技巧:
4、try一個函數(shù)體,形式如下
void fun(type1,type2) try----try放在函數(shù)體后
{
?? 函數(shù)定義
}
catch(typeX){}
這個用法的效果就相當(dāng)于:
void fun()?
{
?? try{函數(shù)定義}
}


5、throw一個函數(shù)體,形式如下:
void fun (); // 能拋出任何類型的異常
void fun () throw(except1,except2,except3)?
?????????????? // 后面括號里面是一個異常參數(shù)表,本例中只能拋出這3中異常
void fun () throw()?? // 參數(shù)表為空,不能拋出異常

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

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

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

?

?

c++ try catch 問題?:

try{} catch(…){}

以前都是用try{} catch(…){}來捕獲C++中一些意想不到的異常, 今天看了Winhack的帖子才知道,這種方法在VC中其實是靠不住的。例如下面的代碼:

  • try
  • {
  • BYTE*?pch?;
  • pch?=?(?BYTE*?)00001234?;???//給予一個非法地址
  • *pch?=?6?;?//對非法地址賦值,會造成Access Violation 異常
  • }
  • catch(...)
  • {
  • AfxMessageBox(?"catched"?)?;
  • }
  • 這段代碼在debug下沒有問題,異常會被捕獲,會彈出”catched”的消息框。 但在Release方式下如果選擇了編譯器代碼優(yōu)化選項,則VC編譯器會去搜索try塊中的代碼, 如果沒有找到throw代碼, 他就會認(rèn)為try catch結(jié)構(gòu)是多余的, 給優(yōu)化掉。 這樣造成在Release模式下,上述代碼中的異常不能被捕獲,從而迫使程序彈出錯誤提示框退出。

    那么能否在release代碼優(yōu)化狀態(tài)下捕獲這個異常呢, 答案是有的。 就是__try, __except結(jié)構(gòu), 上述代碼如果改成如下代碼異常即可捕獲。

  • __try
  • {
  • BYTE*?pch?;
  • pch?=?(?BYTE*?)00001234?;???//給予一個非法地址
  • *pch?=?6?;?//對非法地址賦值,會造成Access Violation 異常
  • }
  • __except(?EXCEPTION_EXECUTE_HANDLER?)
  • {
  • AfxMessageBox(?"catched"?)?;
  • }
  • 但是用__try, __except塊還有問題, 就是這個不是C++標(biāo)準(zhǔn), 而是Windows平臺特有的擴(kuò)展。 而且如果在使用過程中涉及局部對象析構(gòu)函數(shù)的調(diào)用,則會出現(xiàn)C2712?的編譯錯誤。 那么還有沒有別的辦法呢?

    當(dāng)然有, 就是仍然使用C++標(biāo)準(zhǔn)的try{}catch(..){}, 但在編譯命令行中加入?/EHa?的參數(shù)。這樣VC編譯器不會把try catch模塊給優(yōu)化掉了。

    一篇比較好的英文文章談這個問題:?http://members.cox.net/doug_web/eh.htm


    ?

    ?C++中catch(…)如何使用:
    上一篇文章中詳細(xì)講了講C++異常處理模型的trycatch使用語法,其中catch關(guān)鍵字是用來定義catch block的,它后面帶一個參數(shù),用來與異常對象的數(shù)據(jù)類型進(jìn)行匹配。注意catch關(guān)鍵字只能定義一個參數(shù),因此每個catch block只能是一種數(shù)據(jù)類型的異常對象的錯誤處理模塊。如果要想使一個catch block能抓獲多種數(shù)據(jù)類型的異常對象的話,怎么辦?C++標(biāo)準(zhǔn)中定義了一種特殊的catch用法,那就是” catch(…)”。

    感性認(rèn)識

    1、catch(…)到底是一個什么樣的東東,先來個感性認(rèn)識吧!看例子先:

    int main()
    {
    try
    {
    cout << "在 try block 中, 準(zhǔn)備拋出一個異常." << endl;
    //這里拋出一個異常(其中異常對象的數(shù)據(jù)類型是int,值為1)
    throw 1;
    }
    //catch( int& value )
    //注意這里catch語句
    catch( …)
    {
    cout << "在 catch(…) block 中, 拋出的int類型的異常對象被處理" << endl;
    }
    }

      2、哈哈!int類型的異常被catch(…)抓獲了,再來另一個例子:

    int main()
    {
    try
    {
    cout << "在 try block 中, 準(zhǔn)備拋出一個異常." << endl;
    //這里拋出一個異常(其中異常對象的數(shù)據(jù)類型是double,值為0.5)
    throw 0.5;
    }
    //catch( double& value )
    //注意這里catch語句
    catch( …)
    {
    cout << "在 catch(…) block 中, double類型的異常對象也被處理" << endl;
    }
    }

       3、同樣,double類型的異常對象也被catch(…)塊抓獲了。是的,catch(..)能匹配成功所有的數(shù)據(jù)類型的異常對象,包括C++語言提 供所有的原生數(shù)據(jù)類型的異常對象,如int、double,還有char*、int*這樣的指針類型,另外還有數(shù)組類型的異常對象。同時也包括所有自定義 的抽象數(shù)據(jù)類型。例程如下:

    int main()
    {
    try
    {
    cout << "在 try block 中, 準(zhǔn)備拋出一個異常." << endl;
    //這里拋出一個異常(其中異常對象的數(shù)據(jù)類型是char*)
    char* p=0;
    throw p;
    }
    //catch( char* value )
    //注意這里catch語句
    catch( …)
    {
    cout << "在 catch(…) block 中, char*類型的異常對象也被處理" << endl;
    }
    }


    int main()
    {
    try
    {
    cout << "在 try block 中, 準(zhǔn)備拋出一個異常." << endl;
    //這里拋出一個異常(其中異常對象的數(shù)據(jù)類型是int[])
    int a[4];
    throw a;
    }
    //catch( int value[] )
    //注意這里catch語句
    catch( …)
    {
    cout << "在 catch(…) block 中, int[]類型的異常對象也被處理" << endl;
    }
    }

      4、對于抽象數(shù)據(jù)類型的異常對象。catch(…)同樣有效,例程如下:

    class MyException
    {
    public:
    protected:
    int code;
    };

    int main()
    {
    try
    {
    cout << "在 try block 中, 準(zhǔn)備拋出一個異常." << endl;
    //這里拋出一個異常(其中異常對象的數(shù)據(jù)類型是MyException)
    throw MyException();
    }
    //catch(MyException& value )
    //注意這里catch語句
    catch( …)
    {
    cout << "在catch(…) block中, MyException類型的異常對象被處理" << endl;
    }
    }
    對catch(…)有點迷糊?
    1、究竟對catch(…)有什么迷糊呢?還是看例子先吧!
    void main()
    {
    int* p = 0;

    try
    {
    // 注意:下面這條語句雖然不是throw語句,但它在執(zhí)行時會導(dǎo)致系統(tǒng)
    // 出現(xiàn)一個存儲保護(hù)錯誤的異常(access violation exception)
    *p = 13; // causes an access violation exception;
    }
    catch(...)
    {
    //catch(…)能抓獲住上面的access violation exception異常嗎?
    cout << "在catch(…) block中" << endl;
    }
    }

      請問上面的程序運(yùn)行時會出現(xiàn)什么結(jié)果嗎?catch(…)能抓獲住系統(tǒng)中出現(xiàn)的access violation exception異常嗎?朋友們!和我們的主人公阿愚一樣,自己動手去測試一把!
    結(jié)果又如何呢?實際上它有兩種不同的運(yùn)行結(jié)果,在window2000系統(tǒng)下用VC來測試運(yùn)行這個小程序時,發(fā)現(xiàn)程序能輸出"在catch(…) block中"的語句在屏幕上,也即catch(…) 能成功抓獲住系統(tǒng)中出現(xiàn)的access violation exception異常,很厲害吧!但如果這個同樣的程序在linux下用gcc編譯后運(yùn)行時,程序?qū)霈F(xiàn)崩潰,并在屏幕上輸出”segment fault”的錯誤信息。

    主人公阿愚有點急了,也開始有點迷糊了,為什么?為什么?為什么同樣一個程序在兩種不同的系統(tǒng)上有不同的表現(xiàn)呢?其原因就是:對于這種由于硬件或操作 系統(tǒng)出現(xiàn)的系統(tǒng)異常(例如說被零除、內(nèi)存存儲控制異常、頁錯誤等等)時,window2000系統(tǒng)有一個叫做結(jié)構(gòu)化異常處理(Structured Exception Handling,SEH)的機(jī)制,這個東東太厲害了,它能和VC中的C++異常處理模型很好的結(jié)合上(實際上VC實現(xiàn)的C++異常處理模型很大程度上建 立在SEH機(jī)制之上的,或者說它是SEH的擴(kuò)展,后面文章中會詳細(xì)闡述并分析這個久富盛名的SEH,看看catch(…)是如何神奇接管住這種系統(tǒng)異常出 現(xiàn)后的程序控制流的,不過這都是后話)。而在linux系統(tǒng)下,系統(tǒng)異常是由信號處理編程方法來控制的(信號處理編程,signal processing progamming。在介紹unix和linux下如何編程的書籍中,都會有對信號處理編程詳細(xì)的介紹,當(dāng)然執(zhí)著的主人公阿愚肯定對它也不會放過,會深 入到unix沿襲下來的信號處理編程內(nèi)部的實現(xiàn)機(jī)制,并嘗試完善改進(jìn)它,使它也能夠較好地和C++異常處理模型結(jié)合上)。

    那么C++標(biāo)準(zhǔn)中對于這種同一個程序有不同的運(yùn)行結(jié)果有何解釋呢?這里需要注意的是,window2000系統(tǒng)下catch(…)能捕獲住系統(tǒng)異常, 這完全是它自己的擴(kuò)展。在C++標(biāo)準(zhǔn)中并沒有要求到這一點,它只規(guī)定catch(…)必須能捕獲程序中所有通過throw語句拋出的異常。因此上面的這個 程序在linux系統(tǒng)下的運(yùn)行結(jié)果也完全是符合C++標(biāo)準(zhǔn)的。雖然大家也必須承認(rèn)window2000系統(tǒng)下對C++異常處理模型的這種擴(kuò)展確實是一個很 不錯的完善,極大得提高了程序的安全性。

    為什么要用catch(…)這個東東?

    程序員朋友們也許會說,這還有問嗎?這篇文章的一開始不就講到了嗎?catch(…)能夠捕獲多種數(shù)據(jù)類型的異常對象,所以它提供給程序員一種對異常 對象更好的控制手段,使開發(fā)的軟件系統(tǒng)有很好的可靠性。因此一個比較有經(jīng)驗的程序員通常會這樣組織編寫它的代碼模塊,如下:

    void Func()
    {
    try
    {
    // 這里的程序代碼完成真正復(fù)雜的計算工作,這些代碼在執(zhí)行過程中
    // 有可能拋出DataType1、DataType2和DataType3類型的異常對象。
    }
    catch(DataType1& d1)
    {
    }
    catch(DataType2& d2)
    {
    }
    catch(DataType3& d3)
    {
    }
    // 注意上面try block中可能拋出的DataType1、DataType2和DataType3三
    // 種類型的異常對象在前面都已經(jīng)有對應(yīng)的catch block來處理。但為什么
    // 還要在最后再定義一個catch(…) block呢?這就是為了有更好的安全性和
    // 可靠性,避免上面的try block拋出了其它未考慮到的異常對象時導(dǎo)致的程
    // 序出現(xiàn)意外崩潰的嚴(yán)重后果,而且這在用VC開發(fā)的系統(tǒng)上更特別有效,因
    // 為catch(…)能捕獲系統(tǒng)出現(xiàn)的異常,而系統(tǒng)異常往往令程序員頭痛了,現(xiàn)
    // 在系統(tǒng)一般都比較復(fù)雜,而且由很多人共同開發(fā),一不小心就會導(dǎo)致一個
    // 指針變量指向了其它非法區(qū)域,結(jié)果意外災(zāi)難不幸發(fā)生了。catch(…)為這種
    // 潛在的隱患提供了一種有效的補(bǔ)救措施。
    catch(…)
    {?
    }
    }

    還有,特別是VC程序員為了使開發(fā)的系統(tǒng)有更好的可靠性,往往在應(yīng)用程序的入口函數(shù)中(如MFC框架的開發(fā)環(huán)境下 CXXXApp::InitInstance())和工作線程的入口函數(shù)中加上一個頂層的trycatch塊,并且使用catch(…)來捕獲一切所有的 異常,如下:

    BOOL CXXXApp::InitInstance()
    {
    if (!AfxSocketInit())
    {
    AfxMessageBox(IDP_SOCKETS_INIT_FAILED);
    return FALSE;
    }

    AfxEnableControlContainer();

    // Standard initialization
    // If you are not using these features and wish to reduce the size
    // of your final executable, you should remove from the following
    // the specific initialization routines you do not need.

    #ifdef _AFXDLL
    Enable3dControls(); // Call this when using MFC in a shared DLL
    #else
    Enable3dControlsStatic(); // Call this when linking to MFC statically
    #endif


    // 注意這里有一個頂層的trycatch塊,并且使用catch(…)來捕獲一切所有的異常
    try
    {
    CXXXDlg dlg;
    m_pMainWnd = &dlg;
    int nResponse = dlg.DoModal();
    if (nResponse == IDOK)?
    {
    // TODO: Place code here to handle when the dialog is
    // dismissed with OK
    }
    else if (nResponse == IDCANCEL)
    {
    // TODO: Place code here to handle when the dialog is
    // dismissed with Cancel
    }
    }
    catch(…)
    {
    // dump出系統(tǒng)的一些重要信息,并通知管理員查找出現(xiàn)意外異常的原因。
    // 同時想辦法恢復(fù)系統(tǒng),例如說重新啟動應(yīng)用程序等
    }

    // Since the dialog has been closed, return FALSE so that we exit the
    // application, rather than start the application's message pump.
    return FALSE;
    }

       通過上面的例程和分析可以得出,由于catch(…)能夠捕獲所有數(shù)據(jù)類型的異常對象,所以在恰當(dāng)?shù)牡胤绞褂胏atch(…)確實可以使軟件系統(tǒng)有著更 好的可靠性。這確實是大家使用catch(…)這個東東最好的理由。但不要誤會的是,在C++異常處理模型中,不只有catch(…)方法能夠捕獲幾乎所 有類型的異常對象(也許有其它更好的方法,在下一篇文章中主人公阿愚帶大家一同去探討一下),可C++標(biāo)準(zhǔn)中為什么會想到定義這樣一個catch(…) 呢?有過java或C#編程開發(fā)經(jīng)驗的程序員會發(fā)現(xiàn),在它們的異常處理模型中,并沒有這樣類似的一種語法,可這里不得不再次強(qiáng)調(diào)的是,java中的異常處 理模型是C++中的異常處理模型的完善改進(jìn)版,可它反而沒有了catch(…),為何呢?還是先去看看下一章吧,“C++的異常處理和面向?qū)ο蟮木o密關(guān)系 ”。也許大家能找到一個似乎合理的原因。

    ?

    總結(jié)

    以上是生活随笔為你收集整理的c++ 使用throw抛出异常的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。