共用方式為


例外狀況和堆疊回溯 C++ 中

在 C++ 例外狀況機制,將控制項從 throw 陳述式的移動到可以處理這個會擲回型別的第一個 catch 陳述式。當 catch 陳述式到達,在擲回和 Catch 陳述式之間的範圍的所有自動變數稱為 堆疊回溯的流程終結。在回溯堆疊,執行期間所做如下:

  1. 控制項由一般循序執行到達 try 陳述式。在 try 區塊的受到嚴密監控的部分執行。

  2. 如果未在此受到嚴密監控的部分期間擲回,遵循 try 區塊的 catch 子句沒有執行。執行會持續在陳述式中,在以下相關 try 區塊中的最後一個 catch 子句之後。

  3. 如果在這個受到嚴密監控的部分執行期間擲回或處於已嚴密監控的部分直接或間接呼叫的任何地方,例外狀況物件所 throw 運算元建立的物件建立。(這表示複製建構函式可能都包含在內)。此時,編譯器可以處理型別的例外狀況,或 catch 處理常式來處理任何例外狀況的較高的執行內容尋找一個 catch 子句。catch 處理常式會檢查依照其出現的順序,在 try 區塊之後。如果找不到適當的處理常式,下動態 try 封入區塊中檢查。這個處理序會繼續執行,直到最外層 try 封入區塊中檢查。

  4. 如果還是找不到相符的處理常式,或是,如果在回溯過程中發生,但是,在處理常式中取得控制項之前,預先定義的執行階段函式 terminate 呼叫。如果發生例外狀況,在擲回例外狀況後,但是,在回溯開始之前, terminate 呼叫。

  5. 如果找到相符的 catch 管理員,因此,它由值攔截,其型式參數藉由複製例外狀況物件初始化。如果遭到攔截,參考參數初始化參考例外狀況物件。在型式參數初始化後,回溯堆疊的處理序啟動。這會完全建構,但不會終結在 try 區塊開頭之間與 catch 管理員和例外狀況的擲回網站所有自動物件的解構。解構在建構而發生。catch 管理員所執行之程式繼續執行,在為時處理常式為後,在不是 catch 處理常式的第一個陳述式或建構。控制項可以循環時所擲回的例外狀況只輸入 catch 管理員,絕不會透過一 goto 陳述式或一 case 標籤在 switch 陳述式。

堆疊回溯範例

下列範例示範如何將堆疊回溯時,擲回例外狀況時。在執行緒的執行與在 C 的 Throw 陳述式移至 main的 catch 陳述式,並解除繫結每個函式。請注意 Dummy 物件建立並終結的命令,以便在超出範圍。同時也請注意函式未完成 main,除了包含 catch 陳述式。函式 A 從其呼叫永遠不回到 B(),因此, B 從其呼叫永遠不回到 C()。如果您取消 Dummy 指標的定義和對應 DELETE 陳述式,然後執行程式,請注意指標絕不會被刪除。如此會發生什麼情況,當函式不會提供一個例外狀況確保時。如需詳細資訊,請參閱<HOW TO:例外狀況的設計。如果註解 Catch 陳述式,您可以觀察發生了什麼因未處理的例外狀況,就是,當程式終止。

#include <string>
#include <iostream>
using namespace std;
 
class MyException{};
class Dummy
{
    public:
    Dummy(string s) : MyName(s) { PrintMsg("Created Dummy:"); }
    Dummy(const Dummy& other) : MyName(other.MyName){ PrintMsg("Copy created Dummy:"); }
    ~Dummy(){ PrintMsg("Destroyed Dummy:"); }
    void PrintMsg(string s) { cout << s  << MyName <<  endl; }
    string MyName; 
    int level;
};
 
 
void C(Dummy d, int i)
{ 
    cout << "Entering FunctionC" << endl;
    d.MyName = " C";
    throw MyException();   
 
    cout << "Exiting FunctionC" << endl;
}
 
void B(Dummy d, int i)
{
    cout << "Entering FunctionB" << endl;
    d.MyName = "B";
    C(d, i + 1);   
    cout << "Exiting FunctionB" << endl; 
}
 
void A(Dummy d, int i)
{ 
    cout << "Entering FunctionA" << endl;
    d.MyName = " A" ;
  //  Dummy* pd = new Dummy("new Dummy"); //Not exception safe!!!
    B(d, i + 1);
 //   delete pd; 
    cout << "Exiting FunctionA" << endl;   
}
 
 
int main()
{
    cout << "Entering main" << endl;
    try
    {
        Dummy d(" M");
        A(d,1);
    }
    catch (MyException& e)
    {
        cout << "Caught an exception of type: " << typeid(e).name() << endl;
    }
 
    cout << "Exiting main." << endl;
    char c;
    cin >> c;
}
 
/* Output:
    Entering main
    Created Dummy: M
    Copy created Dummy: M
    Entering FunctionA
    Copy created Dummy: A
    Entering FunctionB
    Copy created Dummy: B
    Entering FunctionC
    Destroyed Dummy: C
    Destroyed Dummy: B
    Destroyed Dummy: A
    Destroyed Dummy: M
    Caught an exception of type: class MyException
    Exiting main.
 
*/