日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

c++异常处理机制示例及讲解

發布時間:2023/12/2 c/c++ 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 c++异常处理机制示例及讲解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.


????? 這兩天我寫了一個測試c++異常處理機制的例子,感覺有很好的示范作用,在此貼出來,給c++異常處理的初學者入門。本文后附有c++異常的知識普及,有興趣者也可以看看。

???? 下面的代碼直接貼到你的console工程中,可以運行調試看看效果,并分析c++的異常機制。
??

  • #include?"stdafx.h" ?
  • #include<stdlib.h> ?
  • #include<crtdbg.h> ?
  • #include?<iostream> ?
  • //?內存泄露檢測機制 ?
  • #define?_CRTDBG_MAP_ALLOC? ?
  • #ifdef?_DEBUG ?
  • #define?new?new(_NORMAL_BLOCK,?__FILE__,?__LINE__) ?
  • #endif ?
  • ?
  • //?自定義異常類 ?
  • class?MyExcepction ?
  • { ?
  • public: ?
  • ?
  • ????????//?構造函數,參數為錯誤代碼 ?
  • ????????MyExcepction(int?errorId) ?
  • ????????{ ?
  • ???????? //?輸出構造函數被調用信息 ?
  • ????????????std::cout?<<?"MyExcepction?is?called"?<<?std::endl; ?
  • ????????????m_errorId?=?errorId; ?
  • ????????} ?
  • ?
  • ????????//?拷貝構造函數 ?
  • ????????MyExcepction(?MyExcepction&?myExp) ?
  • ????????{ ?
  • ??????? ?//?輸出拷貝構造函數被調用信息 ?
  • ????????????std::cout?<<?"copy?construct?is?called"?<<?std::endl; ?
  • ????????????this->m_errorId?=?myExp.m_errorId; ?
  • ????????} ?
  • ?
  • ???????~MyExcepction() ?
  • ????????{ ?
  • ????????????//?輸出析構函數被調用信息 ?
  • ????????????std::cout?<<?"~MyExcepction?is?called"?<<?std::endl; ?
  • ????????} ?
  • ?
  • ???????//?獲取錯誤碼 ?
  • ????????int?getErrorId() ?
  • ????????{ ?
  • ????????????return?m_errorId; ?
  • ????????} ?
  • ?
  • private:???? ?
  • ????????//?錯誤碼 ?
  • ????????int?m_errorId; ?
  • }; ?
  • ?
  • int?main(int?argc,?char*?argv[]) ?
  • { ?
  • ????????//?內存泄露檢測機制 ?
  • ????????_CrtSetDbgFlag(?_CRTDBG_ALLOC_MEM_DF?|?_CRTDBG_LEAK_CHECK_DF?); ?
  • ?
  • ????????//?可以改變錯誤碼,以便拋出不同的異常進行測試 ?
  • ????????int?throwErrorCode?=?110; ?
  • ?
  • ???????std::cout?<<?"?input?test?code?:"?<<?std::endl; ?
  • ???????std::cin?>>?throwErrorCode; ?
  • ?
  • ???????try?
  • ???????{ ?
  • ????????????if?(?throwErrorCode?==?110) ?
  • ????????????{ ?
  • ???????????? MyExcepction?myStru(110); ?
  • ?
  • ????????????????//?拋出對象的地址?->?由catch(?MyExcepction*????pMyExcepction)?捕獲 ?
  • ????????????????//?這里該對象的地址拋出給catch語句,不會調用對象的拷貝構造函數 ?
  • ????????????????//?傳地址是提倡的做法,不會頻繁地調用該對象的構造函數或拷貝構造函數 ?
  • ????????????????//?catch語句執行結束后,myStru會被析構掉 ?
  • ????????????????throw????&myStru;???? ?
  • ????????????} ?
  • ????????????else?if?(?throwErrorCode?==?119?) ?
  • ????????????{ ?
  • ???????????? MyExcepction?myStru(119); ?
  • ?
  • ????????????????//?拋出對象,這里會通過拷貝構造函數創建一個臨時的對象傳出給catch ?
  • ????????????????//?由catch(?MyExcepction????myExcepction)?捕獲 ?
  • ????????????????//?在catch語句中會再次調用通過拷貝構造函數創建臨時對象復制這里傳過去的對象 ?
  • ????????????????//?throw結束后myStru會被析構掉 ?
  • ????????????????throw????myStru;???? ?
  • ?????????????} ?
  • ?????????????else?if?(?throwErrorCode?==?120?) ?
  • ?????????????{ ?
  • ??????????????????//?不提倡這樣的拋出方法 ?
  • ??????????????????//?這樣做的話,如果catch(?MyExcepction*????pMyExcepction)中不執行delete操作則會發生內存泄露 ?
  • ?
  • ??????????????????//?由catch(?MyExcepction*????pMyExcepction)?捕獲 ?
  • ??????????????????MyExcepction?*?pMyStru?=?new?MyExcepction(120);? ?
  • ??????????????????throw?pMyStru;???? ?
  • ?????????????} ?
  • ?????????????else?
  • ?????????????{ ?
  • ??????????????????//?直接創建新對象拋出 ?
  • ??????????????????//?相當于創建了臨時的對象傳遞給了catch語句 ?
  • ??????????????????//?由catch接收時通過拷貝構造函數再次創建臨時對象接收傳遞過去的對象 ?
  • ??????????????????//?throw結束后兩次創建的臨時對象會被析構掉 ?
  • ???????????????????throw?MyExcepction(throwErrorCode);???? ?
  • ?????????????}???? ?
  • ????????} ?
  • ????????catch(?MyExcepction*????pMyExcepction) ?
  • ????????{ ?
  • ?????????????//?輸出本語句被執行信息 ?
  • ???????????????std::cout?<<?"執行了?catch(?MyExcepction*????pMyExcepction)?"?<<?std::endl; ?
  • ?
  • ?????????????//?輸出錯誤信息 ?
  • ???????????????std::cout?<<?"error?Code?:?"?<<?pMyExcepction->getErrorId()<<?std::endl; ?
  • ?
  • ????????????//?異常拋出的新對象并非創建在函數棧上,而是創建在專用的異常棧上,不需要進行delete ?
  • ????????????//delete?pMyExcepction; ?
  • ????????} ?
  • ????????catch?(?MyExcepction?myExcepction) ?
  • ????????{ ?
  • ????????????//?輸出本語句被執行信息 ?
  • ????????????std::cout?<<?"執行了?catch?(?MyExcepction?myExcepction)?"?<<?std::endl; ?
  • ?
  • ????????????//?輸出錯誤信息 ?
  • ????????????std::cout?<<?"error?Code?:?"?<<?myExcepction.getErrorId()<<?std::endl; ?
  • ????????} ?
  • ????????catch(...) ?
  • ????????{ ?
  • ?????????????//?輸出本語句被執行信息 ?
  • ?????????????std::cout?<<?"執行了?catch(...)?"?<<?std::endl; ?
  • ?
  • ?????????????//?處理不了,重新拋出給上級 ?
  • ?????????????throw?; ?
  • ????????} ?
  • ?
  • ????????//?暫停 ?
  • ????????int?temp; ?
  • ??????? std::cin?>>?temp; ?
  • ?
  • ???????return?0; ?
  • }?

  • 知識點: c++異常機制

    一、 概述

    C++自身有著非常強的糾錯能力,發展到如今,已經建立了比較完善的異常處理機制。C++的異常情況無非兩種,一種是語法錯誤,即程序中出現了錯誤的語句,函數,結構和類,致使編譯程序無法進行。另一種是運行時發生的錯誤,一般與算法有關。

    關于語法錯誤,不必多說,寫代碼時心細一點就可以解決。C++編譯器的報錯機制可以讓我們輕松地解決這些錯誤。

    第二種是運行時的錯誤,常見的有文件打開失敗、數組下標溢出、系統內存不足等等。而一旦出現這些問題,引發算法失效、程序運行時無故停止等故障也是常有的。這就要求我們在設計軟件算法時要全面。比如針對文件打開失敗的情況,保護的方法有很多種,最簡單的就是使用“return”命令,告訴上層調用者函數執行失敗;另外一種處理策略就是利用c++的異常機制,拋出異常。
    ???
    二、c++異常處理機制

    ??? C++異常處理機制是一個用來有效地處理運行錯誤的非常強大且靈活的工具,它提供了更多的彈性、安全性和穩固性,克服了傳統方法所帶來的問題.
    ???
    ??? 異常的拋出和處理主要使用了以下三個關鍵字: try、 throw 、 catch 。
    ??
    ??? 拋出異常即檢測是否產生異常,在C++中,其采用throw語句來實現,如果檢測到產生異常,則拋出異常。該語句的格式為:
    ??? throw 表達式;
    ??? 如果在try語句塊的程序段中(包括在其中調用的函數)發現了異常,且拋棄了該異常,則這個異常就可以被try語句塊后的某個catch語句所捕獲并處理,捕獲和處理的條件是被拋棄的異常的類型與catch語句的異常類型相匹配。由于C++使用數據類型來區分不同的異常,因此在判斷異常時,throw語句中的表達式的值就沒有實際意義,而表達式的類型就特別重要。
    ?
    try-catch語句形式如下 :

  • try?
  • { ?
  • ????????包含可能拋出異常的語句; ?
  • } ?
  • catch(類型名?[形參名])?//?捕獲特定類型的異常 ?
  • { ?
  • ?
  • } ?
  • catch(類型名?[形參名])?//?捕獲特定類型的異常 ?
  • { ?
  • ?
  • } ?
  • catch(...)????//?三個點則表示捕獲所有類型的異常 ?
  • { ?
  • }?

  • 【范例1】處理除數為0的異常。該范例將上述除數為0的異常可以用try/catch語句來捕獲異常,并使用throw語句來拋出異常,從而實現異常處理,實現代碼如代碼清單1-1所示。
    // 代碼清單1-1

  • #include<iostream.h>?????//包含頭文件 ?
  • #include<stdlib.h> ?
  • ?
  • double?fuc(double?x,?double?y)?//定義函數 ?
  • { ?
  • ????if(y==0) ?
  • ????{ ?
  • ????????throw?y;?????//除數為0,拋出異常 ?
  • ????} ?
  • ????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);????????????????//異常退出程序 ?
  • ????} ?
  • }?
  • 【范例2】自定義異常類型 (在本文開始的代碼中已經給出示范)

    三、異常的接口聲明

    為了加強程序的可讀性,使函數的用戶能夠方便地知道所使用的函數會拋出哪些異常,可以在函數的聲明中列出這個函數可能拋出的所有異常類型,例如:

    void fun() throw( A,B,C,D); 這表明函數fun()可能并且只可能拋出類型(A,B,C,D)及其子類型的異常。

    如果在函數的聲明中沒有包括異常的接口聲明,則此函數可以拋出任何類型的異常,例如: void fun();
    ?
    一個不會拋出任何類型異常的函數可以進行如下形式的聲明:
    ? void fun() thow();

    ?????
    五、異常處理中需要注意的問題

    1. 如果拋出的異常一直沒有函數捕獲(catch),則會一直上傳到c++運行系統那里,導致整個程序的終止

    2. 一般在異常拋出后資源可以正常被釋放,但注意如果在類的構造函數中拋出異常,系統是不會調用它的析構函數的,處理方法是:如果在構造函數中要拋出異常,則在拋出前要記得刪除申請的資源。

    3. 異常處理僅僅通過類型而不是通過值來匹配的,所以catch塊的參數可以沒有參數名稱,只需要參數類型。

    4. 函數原型中的異常說明要與實現中的異常說明一致,否則容易引起異常沖突。
    ?
    5. 應該在throw語句后寫上異常對象時,throw先通過Copy構造函數構造一個新對象,再把該新對象傳遞給 catch.
    ?????? 那么當異常拋出后新對象如何釋放?
    ?????? 異常處理機制保證:異常拋出的新對象并非創建在函數棧上,而是創建在專用的異常棧上,因此它才可以跨接多個函數而傳遞到上層,否則在棧清空的過程中就會被銷毀。所有從try到throw語句之間構造起來的對象的析構函數將被自動調用。但如果一直上溯到main函數后還沒有找到匹配的catch塊,那么系統調用terminate()終止整個程序,這種情況下不能保證所有局部對象會被正確地銷毀。
    ??
    6. catch塊的參數推薦采用地址傳遞而不是值傳遞,不僅可以提高效率,還可以利用對象的多態性。另外,派生類的異常撲獲要放到父類異常撲獲的前面,否則,派生類的異常無法被撲獲。
    ??
    7. 編寫異常說明時,要確保派生類成員函數的異常說明和基類成員函數的異常說明一致,即派生類改寫的虛函數的異常說明至少要和對應的基類虛函數的異常說明相同,甚至更加嚴格,更特殊。

    本文出自 “對影成三人” 博客,請務必保留此出處http://ticktick.blog.51cto.com/823160/191881

    總結

    以上是生活随笔為你收集整理的c++异常处理机制示例及讲解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。