c++中的try-catch及throw

hisun9發表於2024-11-07

C++ 使用 try-catch 語句來捕獲和處理異常。try 塊包含可能發生錯誤的程式碼,而 catch 塊則用來捕獲並處理錯誤。

try-catch 語句的基本結構

try {
    // 可能丟擲異常的程式碼
} catch (exception_type1 e1) {
    // 處理異常型別 1
} catch (exception_type2 e2) {
    // 處理異常型別 2
} catch (...) {
    // 捕獲所有型別的異常
}

具體解釋:

  1. try 塊

    try 塊包含可能發生異常的程式碼。

    如果 try 塊中的程式碼發生了異常,程式會跳轉到相應的 catch 塊進行異常處理。

  2. catch 塊

    catch 用來捕獲由 try 塊丟擲的異常,並進行處理。

    可以有多個 catch 塊,每個 catch 塊負責處理特定型別的異常。

    如果 catch 中的異常型別與丟擲的異常型別匹配,程式會執行該 catch 塊中的程式碼。

  3. catch (...)

    catch(...) 是一個萬用字元,用來捕獲所有型別的異常。

    這在無法確定丟擲異常的具體型別時特別有用

舉兩個例子說明

  1. 第一個例子

    #include <iostream>
    using namespace std;
    
    int main() {
        try {
            int a = 5;
            int b = 0;
            if (b == 0) {
                throw "Division by zero error!";
            }
            cout << a / b << endl;
        } catch (const char* e) {
            cout << "Error: " << e << endl;  // 捕獲並處理除零錯誤
        }
        return 0;
    }
    

    輸出如下:

    img

    解釋:

    在 try 塊中,程式嘗試執行可能出錯的程式碼。

    如果發生異常(這裡是透過 throw 手動丟擲除零錯誤),catch 塊會捕獲到異常並進行處理。

  • 第二個例子

    #include <iostream>
    #include <stdexcept>  // 包含異常類
    
    using namespace std;
    
    int main() {
        try {
            int a = 10, b = 0;
            if (b == 0) {
                throw std::runtime_error("Division by zero error!"); // 丟擲執行時錯誤
            }
            cout << a / b << endl;
        } catch (const std::runtime_error& e) {
            cout << "Caught a runtime error: " << e.what() << endl;  // 捕獲並處理 std::runtime_error
        } catch (const std::exception& e) {
            cout << "Caught a general exception: " << e.what() << endl;  // 捕獲所有 std::exception 型別的異常
        } catch (...) {
            cout << "Caught an unknown error!" << endl;  // 捕獲其他所有型別的異常
        }
        
        return 0;
    }
    

    輸出如下:

    img

    解釋:

    try 塊中的程式碼試圖執行可能會丟擲異常的操作。例如,在這個例子中,我們故意將 b 設定為 0,模擬除零錯誤。

    如果程式遇到除零錯誤,丟擲一個 std::runtime_error 型別的異常。

    catch (const std::runtime_error& e) 塊捕獲 std::runtime_error 型別的異常,並輸出錯誤資訊。

    catch (const std::exception& e) 是更廣泛的異常型別,它會捕獲所有繼承自 std::exception 類的異常(包括 std::runtime_error)。

    catch (...) 捕獲所有其他型別的異常,確保即使沒有明確處理某種異常型別,程式也不會崩潰。

throw 語句:丟擲異常

在 C++ 中,throw 關鍵字用於丟擲異常。可以在任何地方丟擲異常,通常是在遇到錯誤或不符合預期的條件時。

throw some_exception;  // 丟擲一個異常

常見的異常型別

C++ 標準庫定義了幾種常見的異常型別。可以選擇丟擲這些異常型別之一,或者建立自己的異常類。

  • std::exception:這是所有標準異常類的基類,所有其他標準異常類都繼承自它。

  • std::runtime_error:執行時錯誤,表示程式執行時發生的錯誤。

  • std::logic_error:邏輯錯誤,表示程式的邏輯上有問題,比如越界訪問陣列等。

  • std::out_of_range:越界錯誤,通常用於容器類(如 std::vector)訪問越界元素時丟擲的異常。

  • std::invalid_argument:無效引數錯誤,表示傳遞給函式的引數不合法。

  • std::bad_alloc:記憶體分配錯誤,當 new 操作失敗時丟擲此異常。

自定義異常類

也可以建立自己的異常類,繼承自 std::exception 或其派生類,以便在程式中丟擲和捕獲特定型別的異常。

#include <iostream>
#include <exception>

class MyException : public std::exception {
public:
    const char* what() const noexcept override {
        return "My custom exception occurred!";
    }
};

int main() {
    try {
        throw MyException();  // 丟擲自定義異常
    } catch (const MyException& e) {
        std::cout << "Caught custom exception: " << e.what() << std::endl;
    }

    return 0;
}

輸出如下:

img

異常的傳播和處理

當 throw 丟擲異常時,異常會沿著呼叫棧向上傳遞,直到找到一個匹配的 catch 塊。

如果沒有合適的 catch 塊捕獲異常,程式會終止並顯示未處理的異常資訊。

比如:

#include <iostream>
#include <stdexcept>  // 包含標準異常型別

using namespace std;

int main() {
    try {
        cout << "Throwing an exception..." << endl;
        throw std::runtime_error("This is a runtime error!");  // 丟擲一個執行時錯誤
    }
    // 這裡只捕獲 std::logic_error 型別的異常,忽略 std::runtime_error
    catch (const std::logic_error& e) {
        cout << "Caught logic_error: " << e.what() << endl;
    }

    cout << "This will not be printed if an exception is thrown!" << endl;
    return 0;
}

輸出如下:

img

異常處理的注意事項

異常的安全性:捕獲異常時要確保程式的狀態一致性。如果在 catch 塊中處理異常時發生了額外的錯誤,可能導致程式不穩定。

效能問題:異常處理會增加程式的執行時開銷,尤其是在頻繁丟擲和捕獲異常的情況下。因此,異常處理應該只用於真正的錯誤,而不是正常的程式流控制。

相關文章