国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

C++中異常處理的基本思想及throw語句拋出異常的使用

2020-05-23 14:06:58
字體:
來源:轉載
供稿:網友
這篇文章主要介紹了C++中異常處理的基本思想及throw類拋出異常的使用,也深入談到了異常被拋出后的棧解旋unwinding過程,需要的朋友可以參考下
 

異常處理基本思想
C++的異常處理的基本思想大致可以概括為傳統錯誤處理機制、通過函數返回值來處理錯誤。

C++,異常處理,throw語句,拋出異常

1)C++的異常處理機制使得異常的引發和異常的處理不必在同一個函數中,這樣底層的函數可以著重解決具體問題,而不必過多的考慮異常的處理。上層調用者可以再適當的位置設計對不同類型異常的處理。
2)異常是專門針對抽象編程中的一系列錯誤處理的,C++中不能借助函數機制,因為棧結構的本質是先進后出,依次訪問,無法進行跳躍,但錯誤處理的特征卻是遇到錯誤信息就想要轉到若干級之上進行重新嘗試,如圖

C++,異常處理,throw語句,拋出異常

3)異常超脫于函數機制,決定了其對函數的跨越式回跳。
4)異常跨越函數

異常基本語法

C++,異常處理,throw語句,拋出異常

1) 若有異常則通過throw操作創建一個異常對象并拋擲。
2) 將可能拋出異常的程序段嵌在try塊之中。控制通過正常的順序執行到達try語句,然后執行try塊內的保護段。
3) 如果在保護段執行期間沒有引起異常,那么跟在try塊后的catch子句就不執行。程序從try塊后跟隨的最后一個catch子句后面的語句繼續執行下去。
4) catch子句按其在try塊后出現的順序被檢查。匹配的catch子句將捕獲并處理異常(或繼續拋擲異常)。
5) 如果匹配的處理器未找到,則運行函數terminate將被自動調用,其缺省功能是調用abort終止程序。
6)處理不了的異常,可以在catch的最后一個分支,使用throw語法,向上扔
7)異常機制與函數機制互不干涉,但捕捉的方式是基于類型匹配。捕捉相當于函數返回類型的匹配,而不是函數參數的匹配,所以捕捉不用考慮一個拋擲中的多種數據類型匹配問題。
catch代碼塊必須出現在try后,并且在try塊后可以出現多個catch代碼塊,以捕捉各種不同類型的拋擲。
異常機制是基于這樣的原理:程序運行實質上是數據實體在做一些操作,因此發生異常現象的地方,一定是某個實體出了差錯,該實體所對應的數據類型便作為拋擲和捕捉的依據。
8)異常捕捉嚴格按照類型匹配
 異常捕捉的類型匹配之苛刻程度可以和模板的類型匹配媲美,它不允許相容類型的隱式轉換,比如,拋擲char類型用int型就捕捉不到.例如下列代碼不會輸出“int exception.”,從而也不會輸出“That's ok.” 因為出現異常后提示退出

int main(){   try{     throw ‘H';   }   catch (int){     cout << "int exception./n";   }   cout << "That's ok./n";    return 0; } 

棧解旋(unwinding)
異常被拋出后,從進入try塊起,到異常被拋擲前,這期間在棧上的構造的所有對象,都會被自動析構。析構的順序與構造的順序相反。這一過程稱為棧的解旋(unwinding)。

#include <iostream> #include <cstdio> using namespace std;   class MyException {};  class Test { public:   Test(int a = 0, int b = 0)   {     this->a = a;     this->b = b;     cout << "Test 構造函數執行" << "a:" << a << " b: " << b << endl;   }   void printT()   {     cout << "a:" << a << " b: " << b << endl;   }   ~Test()   {     cout << "Test 析構函數執行" << "a:" << a << " b: " << b << endl;   } private:   int a;   int b; };  void myFunc() throw (MyException) {   Test t1;   Test t2;    cout << "定義了兩個棧變量,異常拋出后測試棧變量的如何被析構" << endl;    throw MyException(); }  int main() {   //異常被拋出后,從進入try塊起,到異常被拋擲前,這期間在棧上的構造的所有對象,   //都會被自動析構。析構的順序與構造的順序相反。   //這一過程稱為棧的解旋(unwinding)   try   {     myFunc();   }   //catch(MyException &e) //這里不能訪問異常對象   catch (MyException) //這里不能訪問異常對象   {     cout << "接收到MyException類型異常" << endl;   }   catch (...)   {     cout << "未知類型異常" << endl;   }    return 0; } 

異常接口聲明
1)為了加強程序的可讀性,可以在函數聲明中列出可能拋出的所有異常類型,例如:
void func() throw (A, B, C , D); //這個函數func()能夠且只能拋出類型A B C D及其子類型的異常。
2)如果在函數聲明中沒有包含異常接口聲明,則次函數可以拋擲任何類型的異常,例如:
void func();
3)一個不拋擲任何類型異常的函數可以聲明為:
void func() throw();
4) 如果一個函數拋出了它的異常接口聲明所不允許拋出的異常,unexpected函數會被調用,該函數默認行為調用terminate函數中止程序。

傳統處理錯誤

#include <iostream> #include <cstdio> using namespace std;  // 傳統的錯誤處理機制 int myStrcpy(char *to, char *from) {   if (from == NULL) {     return 1;   }   if (to == NULL) {     return 2;   }    // copy時的場景檢查   if (*from == 'a') {     return 3; // copy時錯誤   }   while (*from != '/0') {     *to = *from;     to++;     from++;   }   *to = '/0';    return 0; }  int main() {   int ret = 0;   char buf1[] = "zbcdefg";   char buf2[1024] = { 0 };    ret = myStrcpy(buf2, buf1);   if (ret != 0) {     switch (ret) {     case 1:       cout << "源buf出錯!/n";       break;     case 2:       cout << "目的buf出錯!/n";       break;     case 3:       cout << "copy過程出錯!/n";       break;     default:       cout << "未知錯誤!/n";       break;     }   }   cout << "buf2:/n" << buf2;   cout << endl;    return 0; } 

throw char*

#include <iostream> #include <cstdio> using namespace std;  // throw char * void myStrcpy(char *to, char *from) {   if (from == NULL) {     throw "源buf出錯";   }   if (to == NULL) {     throw "目的buf出錯";   }    // copy時的場景檢查   if (*from == 'a') {     throw "copy過程出錯"; // copy時錯誤   }   while (*from != '/0') {     *to = *from;     to++;     from++;   }   *to = '/0';    return; }  int main() {   int ret = 0;   char buf1[] = "abcdefg";   char buf2[1024] = { 0 };    try   {     myStrcpy(buf2, buf1);   }   catch (int e) // e可以寫可以不寫   {     cout << e << "int類型異常" << endl;   }   catch (char *e)   {     cout << "char* 類型異常" << endl;   }   catch (...)   {   };   cout << endl;    return 0; } 

throw 類對象

#include <iostream> #include <cstdio> using namespace std;  class BadSrcType {}; class BadDestType {}; class BadProcessType { public:   BadProcessType()   {     cout << "BadProcessType構造函數do /n";   }     BadProcessType(const BadProcessType &obj)   {     cout << "BadProcessType copy構造函數do /n";   }    ~BadProcessType()   {     cout << "BadProcessType析構函數do /n";   }  }; 

  
throw 類對象、類型異常  

void my_strcpy3(char *to, char *from) {   if (from == NULL)   {     throw BadSrcType();   }   if (to == NULL)   {     throw BadDestType();   }    //copy是的 場景檢查   if (*from == 'a')   {     printf("開始 BadProcessType類型異常 /n");     throw BadProcessType(); //會不會產生一個匿名對象?   }    if (*from == 'b')   {     throw &(BadProcessType()); //會不會產生一個匿名對象?   }    if (*from == 'c')   {     throw new BadProcessType; //會不會產生一個匿名對象?   }   while (*from != '/0')   {     *to = *from;     to++;     from++;   }   *to = '/0'; }  int main() {   int ret = 0;   char buf1[] = "cbbcdefg";   char buf2[1024] = { 0 };    try   {     //my_strcpy1(buf2, buf1);     //my_strcpy2(buf2, buf1);     my_strcpy3(buf2, buf1);   }   catch (int e) //e可以寫 也可以不寫   {     cout << e << " int類型異常" << endl;   }   catch (char *e)   {     cout << e << " char* 類型異常" << endl;   }    //---   catch (BadSrcType e)   {     cout << " BadSrcType 類型異常" << endl;   }   catch (BadDestType e)   {     cout << " BadDestType 類型異常" << endl;   }   //結論1: 如果 接受異常的時候 使用一個異常變量,則copy構造異常變量.    /*   catch( BadProcessType e) //是把匿名對象copy給e 還是e還是那個匿名對象   {   cout << " BadProcessType 類型異常" << endl;   }   */   /*結論2: 使用引用的話 會使用throw時候的那個對象   catch( BadProcessType &e) //是把匿名對象copy給e 還是e還是那個匿名對象   {   cout << " BadProcessType 類型異常" << endl;   }   */    //結論3: 指針可以和引用/元素寫在一塊 但是引用和元素不能寫在一塊   catch (BadProcessType *e) //是把匿名對象copy給e 還是e還是那個匿名對象   {     cout << " BadProcessType 類型異常" << endl;     delete e;   }    //結論4: 類對象時, 使用引用比較合適     // --   catch (...)   {     cout << "未知 類型異常" << endl;   }    return 0; } 
 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 定远县| 静宁县| 南雄市| 巴青县| 三江| 永年县| 德令哈市| 谢通门县| 涞水县| 珲春市| 新源县| 台北市| 新昌县| 施甸县| 兰坪| 平泉县| 汾阳市| 巴马| 景泰县| 连云港市| 武定县| 南投市| 定西市| 霸州市| 从化市| 浠水县| 普定县| 长宁区| 安多县| 澳门| 吉首市| 汝州市| 昌平区| 阜平县| 丰都县| 永善县| 无极县| 林芝县| 资中县| 岐山县| 东阳市|