從零開始學C++之異常(二):程式錯誤、異常(文法、拋出、捕獲、傳播)、棧展開

來源:互聯網
上載者:User

一、程式錯誤

編譯錯誤,即語法錯誤。程式就無法被產生運行代碼。
執行階段錯誤

不可預料的邏輯錯誤

可以預料的運行異常

例如:

動態分配空間時可能不會成功

開啟檔案可能會失敗

除法運算時分母可能為0

整數相乘可能溢出

數組越界……


二、異常

(一)、異常文法

throw  運算式;

try
{
    //try語句塊
}
catch(類型1  參數1)
{
    //針對類型1的異常處理
}
catch (類型2  參數2)
{
    //針對類型2的異常處理
}

catch (類型n  參數n)
{
    //針對類型n的異常處理
}


(二)、異常拋出

可以拋出內建類型異常也可以拋出自訂類型異常
throw拋出一個類對象會調用拷貝建構函式
異常發生之前建立的局部對象被銷毀,這一過程稱為棧展開


(三)、異常捕獲

一個異常處理器一般只捕捉一種類型的異常
異常處理器的參數類型和拋出異常的類型相同
…表示可以捕獲任何異常


 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include <iostream>
#include <string>
using namespace std;

class MyException
{
public:
    MyException(const char *message)
        : message_(message)
    {
        cout << "MyException ..." << endl;
    }
    MyException(const MyException &other) : message_(other.message_)
    {
        cout << "Copy MyException ..." << endl;
    }
    ~MyException()
    {
        cout << "~MyException" << endl;
    }

    const char *what() const
    {
        return message_.c_str();
    }
private:
    string message_;
};
double Divide(double a, double b)
{
    if (b == 0.0)
    {
        MyException e("division by zero");
        throw e;
        /*throw MyException("division by zero");*/
        //throw 1;
    }
    else
        return a / b;
}
int main(void)
{
    try
    {
        cout << Divide(5.0, 0.0) << endl;
    }
    catch (MyException &e)
    {
        cout << e.what() << endl;
    }
    //catch (int)
    //{
    //  cout<<"int exception ..."<<endl;
    //}
    catch (double)
    {
        cout << "double exception ..." << endl;
    }
    catch (...)
    {
        cout << "catch a exception ..." << endl;
    }
}



程式自訂一個異常類型MyException,從輸出可以看出,Divide函數內先構造一個MyException對象e,調用建構函式,因為e是局部對象需要被析構,在析構前先調用拷貝建構函式構造另一個對象,這個對象將被catch 引用,最後這個對象在catch末尾也將被析構。

假設沒有構造局部對象,直接throw , 如 throw MyException("division by zero"); 那麼將不會調用拷貝建構函式,只存在一個對象,在catch的末尾被析構。

假設throw 1; 而沒有對應的catch (int) ,即使存在catch (double) 也捕獲不到,不會做類型轉換,此時會由catch (...) 捕獲到,...表示可以捕獲任何異常。


(四)、異常傳播

1、try塊可以嵌套
2、程式按順序尋找匹配的異常處理器,拋出的異常將被第一個類型符合的異常處理器捕獲
如果內層try塊後面沒有找到合適的異常處理器,該異常向外傳播,到外層try塊後面的catch塊中尋找
3、沒有被捕獲的異常將調用terminate函數,terminate函數預設調用abort終止程式的執行
可以使用set_terminate函數指定terminate函數在調用abort之前將調用的函數


 C++ Code 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void MyTerminate()
{
    cout << "MyTerminate ..." << endl;
}

int main(void)
{
    set_terminate(MyTerminate);
    try
    {
        try
        {
            throw MyException("test exception");
        }
        catch (int)
        {
            cout << "Inner ..." << endl;
            cout << "catch a int exception" << endl;
        }
        //catch (MyException& e)
        //{
        //  cout<<"Inner ..."<<endl;
        //  cout<<e.what()<<endl;
        //  throw e;
        //}
    }
    catch (int)
    {
        cout << "Outer ..." << endl;
        cout << "catch a int exception" << endl;
    }
    catch (MyException &e)
    {
        cout << "Outer ..." << endl;
        cout << e.what() << endl;
    }
}



其中MyException類如上,程式中將內層的catch (MyException& e) 屏蔽了,所以由外層的catch (MyException& e) 捕獲,假設將兩個都注釋掉的話,因為沒有找到合適的catch, 那麼terminate 函數會被調用,並且由於事先set_terminate
函數設定了abort調用之前被調用的函數MyTerminate,故先輸出MyTerminate ...然後程式被終止。


三、棧展開

沿著嵌套調用連結向上尋找,直至為異常找到一個catch子句。這個過程稱之為棧展開。

為局部對象調用解構函式

解構函式應該從不拋出異常

棧展開期間會執行解構函式,在執行解構函式的時候,已經引發的異常但還沒處理,如果這個過程中解構函式又拋出新的異常,將會調用標準庫的terminate函數。

異常與建構函式

建構函式中可以拋出異常。如果在建構函式函數中拋出異常,則可能該對象只是部分被構造。即使對象只是被部分構造,也要保證銷毀已構造的成員。(如果成員是指標p,因為解構函式不會被調用,故不會執行一般的delete p; 很可能造成記憶體流失)



參考:

C++ primer 第四版
Effective C++ 3rd
C++編程規範


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.