欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++異常處理從基礎(chǔ)到應(yīng)用全面解析

 更新時(shí)間:2025年11月03日 11:12:17   作者:我星期八休息  
C/C++異常處理是一個(gè)關(guān)鍵的主題,特別是在這兩種廣泛使用的編程語(yǔ)言中,它們提供了處理程序運(yùn)行期間遇到的非正常情況的能力,這篇文章主要介紹了C++異常處理從基礎(chǔ)到應(yīng)用的相關(guān)資料,需要的朋友可以參考下

前言

本文將深入探討C++異常處理機(jī)制,涵蓋核心概念、使用方法和最佳實(shí)踐,幫助開(kāi)發(fā)者構(gòu)建更健壯的應(yīng)用程序。

1. 異常處理的基本概念

1.1 什么是異常處理?

異常處理是C++中處理程序運(yùn)行時(shí)錯(cuò)誤的重要機(jī)制。與C語(yǔ)言通過(guò)錯(cuò)誤碼處理錯(cuò)誤的方式不同,C++異常機(jī)制通過(guò)拋出對(duì)象來(lái)傳遞錯(cuò)誤信息,提供了更加豐富和靈活的錯(cuò)誤處理能力。

傳統(tǒng)錯(cuò)誤碼處理 vs 異常處理對(duì)比:

特性錯(cuò)誤碼處理異常處理
錯(cuò)誤信息有限的錯(cuò)誤碼豐富的對(duì)象信息
傳播方式手動(dòng)檢查返回值自動(dòng)沿調(diào)用棧傳播
代碼結(jié)構(gòu)錯(cuò)誤處理與業(yè)務(wù)邏輯混合清晰的分離關(guān)注點(diǎn)
性能無(wú)額外開(kāi)銷有棧展開(kāi)開(kāi)銷

1.2 異常的基本語(yǔ)法

C++異常處理使用三個(gè)關(guān)鍵字:try、catch 和 throw,構(gòu)成完整的異常處理機(jī)制:

// 拋出異常
throw exception_object;

// 捕獲異常
try {
    // 可能拋出異常的代碼
} catch (exception_type1& e) {
    // 處理特定類型異常
} catch (exception_type2& e) {
    // 處理其他類型異常
} catch (...) {
    // 處理所有其他異常
}

2. 異常的拋出和捕獲機(jī)制

2.1 拋出異常

當(dāng)程序檢測(cè)到錯(cuò)誤時(shí),通過(guò)throw表達(dá)式拋出一個(gè)異常對(duì)象:

double Divide(int a, int b) {
    if (b == 0) {
        // 拋出字符串異常
        throw "Division by zero condition!";
    }
    return static_cast<double>(a) / b;
}

拋出異常的關(guān)鍵特性:

  • throw后面的語(yǔ)句不會(huì)被執(zhí)行

  • 控制權(quán)立即轉(zhuǎn)移到匹配的catch塊

  • 會(huì)創(chuàng)建異常對(duì)象的拷貝

2.2 棧展開(kāi)

  • 拋出異常后,程序暫停當(dāng)前函數(shù)的執(zhí)行,開(kāi)始尋找與之匹配的catch子句,首先檢查throw本身是否在try塊內(nèi)部,如果在則查找匹配的catch語(yǔ)句,如果有匹配的,則跳到catch的地方進(jìn)行處理。

  • 如果當(dāng)前函數(shù)中沒(méi)有try/catch子句,或者有try/catch子句但是類型不匹配,則退出當(dāng)前函數(shù),繼續(xù) 在外層調(diào)用函數(shù)鏈中查找,上述查找的catch過(guò)程被稱為棧展開(kāi)。

  • 如果到達(dá)main函數(shù),依舊沒(méi)有找到匹配的catch子句,程序會(huì)調(diào)用標(biāo)準(zhǔn)庫(kù)的terminate函數(shù)終止程序。

  • 如果找到匹配的catch子句處理后,catch子句代碼會(huì)繼續(xù)執(zhí)行。

代碼演示棧展開(kāi):

void func1() {
    throw string("異常來(lái)自func1");
}

void func2() {
    func1();  // 異常從這里拋出
}

void func3() {
    func2();
}

int main() {
    try {
        func3();  // 調(diào)用鏈: main -> func3 -> func2 -> func1
    } catch (const string& e) {
        cout << "捕獲異常: " << e << endl;
    }
    return 0;
}

3. 異常匹配機(jī)制

3.1 匹配規(guī)則

異常匹配遵循特定規(guī)則,支持以下轉(zhuǎn)換類型:

轉(zhuǎn)換類型示例說(shuō)明
權(quán)限縮小throw int → catch(const int)非常量到常量
指針轉(zhuǎn)換throw int[] → catch(int*)數(shù)組到指針
繼承轉(zhuǎn)換

throw Derived → catch(Base&)

派生類到基類

3.2 繼承體系中的異常處理

在項(xiàng)目實(shí)踐中,我們通常采用繼承體系來(lái)組織異常類結(jié)構(gòu):

// 異?;?
class Exception {
public:
    Exception(const string& errmsg, int id) 
        : _errmsg(errmsg), _id(id) {}
    
    virtual string what() const {
        return _errmsg;
    }
    
    int getid() const {
        return _id;
    }

protected:
    string _errmsg;
    int _id;
};

// 具體異常類型
class SqlException : public Exception {
public:
    SqlException(const string& errmsg, int id, const string& sql)
        : Exception(errmsg, id), _sql(sql) {}
    
    virtual string what() const override {
        return "SqlException:" + _errmsg + "->" + _sql;
    }

private:
    const string _sql;
};

class CacheException : public Exception {
public:
    CacheException(const string& errmsg, int id)
        : Exception(errmsg, id) {}
    
    virtual string what() const override {
        return "CacheException:" + _errmsg;
    }
};

繼承異常體系的優(yōu)勢(shì):

  1. 提供統(tǒng)一的異常處理接口

  2. 實(shí)現(xiàn)異常的多態(tài)處理能力

  3. 提升代碼的可擴(kuò)展性和可維護(hù)性

4. 異常重新拋出

有時(shí)catch到一個(gè)異常對(duì)象后,需要對(duì)錯(cuò)誤進(jìn)行分類,其中的某種異常錯(cuò)誤需要進(jìn)行特殊的處理,其他錯(cuò)誤則重新拋出異常給外層調(diào)用鏈處理。捕獲異常后需要重新拋出,直接 throw;  就可以把捕獲的對(duì)象直接拋出。

void SendMsg(const string& s) {
    // 最多重試3次
    for (size_t i = 0; i < 4; i++) {
        try {
            _SeedMsg(s);  // 嘗試發(fā)送消息
            break;        // 成功則退出循環(huán)
        } catch (const Exception& e) {
            // 網(wǎng)絡(luò)不穩(wěn)定錯(cuò)誤,嘗試重試
            if (e.getid() == 102) {
                if (i == 3) {
                    throw;  // 重試3次后仍失敗,重新拋出
                }
                cout << "開(kāi)始第" << i + 1 << "次重試" << endl;
            } else {
                throw;  // 其他錯(cuò)誤直接重新拋出
            }
        }
    }
}

5. 異常安全

5.1 資源泄漏問(wèn)題

5.1.1 問(wèn)題定義

資源泄漏是指程序在運(yùn)行過(guò)程中未能正確釋放已分配的系統(tǒng)資源(如內(nèi)存、文件句柄、數(shù)據(jù)庫(kù)連接等),導(dǎo)致這些資源無(wú)法被其他程序或后續(xù)操作重新利用的現(xiàn)象。

5.1.2 常見(jiàn)類型

(1) 內(nèi)存泄漏

  • 動(dòng)態(tài)分配的內(nèi)存未被釋放

  • 示例:

    void memory_leak() {
        char *buffer = malloc(1024);
        // 忘記調(diào)用 free(buffer)
    }
    

(2)文件句柄泄漏

  • 打開(kāi)的文件未關(guān)閉

  • 示例:

    def file_leak():
        f = open("data.txt", "r")
        # 忘記調(diào)用 f.close()
    

(3)數(shù)據(jù)庫(kù)連接泄漏

  • 獲取的數(shù)據(jù)庫(kù)連接未釋放

  • 示例(Java JDBC):

    public void dbLeak() throws SQLException {
        Connection conn = DriverManager.getConnection(url);
        // 忘記調(diào)用 conn.close()
    }
    

(4)圖形資源泄漏

  • 圖形界面中的GDI對(duì)象未釋放

  • 示例(Windows API):

    void gdiLeak() {
        HDC hdc = GetDC(hWnd);
        // 忘記調(diào)用 ReleaseDC(hWnd, hdc)
    }
    

5.1.3 影響與后果

  1. 系統(tǒng)性能下降:累積的泄漏會(huì)導(dǎo)致可用資源減少

  2. 程序崩潰:當(dāng)資源耗盡時(shí)程序可能異常終止

  3. 系統(tǒng)不穩(wěn)定:可能影響其他程序的正常運(yùn)行

  4. 安全風(fēng)險(xiǎn):可能被利用進(jìn)行拒絕服務(wù)攻擊

5.2 解決方案

方案1:使用try-catch確保資源釋放

void SafeFunc1() {
    int* array = new int[10];
    
    try {
        SomeOperationThatMightThrow();
    } catch (...) {
        delete[] array;  // 異常時(shí)釋放資源
        throw;           // 重新拋出異常
    }
    
    delete[] array;      // 正常流程釋放資源
}

方案2:使用RAII技術(shù)(推薦)

RAII(Resource Acquisition Is Initialization)是C++中管理資源的重要技術(shù),其核心思想是將資源生命周期與對(duì)象生命周期綁定。

// 使用智能指針自動(dòng)管理資源
#include <memory>

void SafeFunc2() {
    std::unique_ptr<int[]> array(new int[10]);
    
    // 即使拋出異常,array也會(huì)自動(dòng)釋放
    SomeOperationThatMightThrow();
    
    // 不需要手動(dòng)delete,unique_ptr會(huì)自動(dòng)處理
}

5.3 析構(gòu)函數(shù)中的異常處理

在析構(gòu)函數(shù)中拋出異常是極其危險(xiǎn)的編程實(shí)踐,可能導(dǎo)致程序異常終止或資源泄漏。主要原因包括:

1. 棧展開(kāi)機(jī)制沖突 當(dāng)異常發(fā)生時(shí),C++會(huì)進(jìn)行棧展開(kāi)(stack unwinding)過(guò)程,在此期間會(huì)調(diào)用對(duì)象的析構(gòu)函數(shù)。如果析構(gòu)函數(shù)本身又拋出異常,就會(huì)導(dǎo)致同時(shí)存在兩個(gè)未處理的異常,此時(shí)程序會(huì)調(diào)用 std::terminate() 強(qiáng)制終止。

示例場(chǎng)景:

class ResourceHolder {
public:
    ~ResourceHolder() {
        if (cleanup_failed) {
            throw std::runtime_error("Cleanup failed"); // 危險(xiǎn)操作!
        }
    }
};

2. 資源泄漏風(fēng)險(xiǎn) 析構(gòu)函數(shù)通常負(fù)責(zé)釋放資源,如果拋出異常,可能導(dǎo)致資源釋放不完全。例如:

  1. 未正確關(guān)閉文件描述符

  2. 未及時(shí)釋放內(nèi)存資源

  3. 未斷開(kāi)數(shù)據(jù)庫(kù)連接

3. 推薦處理方式應(yīng)在析構(gòu)函數(shù)內(nèi)部捕獲并處理所有異常:

~ResourceHolder() {
    try {
        // 資源清理代碼
    } catch (...) {
        // 記錄日志或采取其他恢復(fù)措施
        std::cerr << "析構(gòu)中發(fā)生異常" << std::endl;
    }
}

4. 特殊注意事項(xiàng)

  • 對(duì)于noexcept聲明的析構(gòu)函數(shù),拋出異常會(huì)直接導(dǎo)致std::terminate調(diào)用

  • 某些標(biāo)準(zhǔn)庫(kù)容器(如std::vector)對(duì)元素類型的析構(gòu)函數(shù)有異常安全要求

  • 在多重繼承場(chǎng)景下,異常處理會(huì)更加復(fù)雜

安全實(shí)踐建議:

  1. 避免在析構(gòu)函數(shù)中執(zhí)行可能拋出異常的操作

  2. 如果必須執(zhí)行,確保在析構(gòu)函數(shù)內(nèi)部處理所有異常

  3. 使用RAII模式管理資源,將復(fù)雜操作移到普通成員函數(shù)中

6. 異常規(guī)范

6.1 C++98 vs C++11異常規(guī)范

版本語(yǔ)法說(shuō)明
C++98throw()不拋出任何異常
C++98throw(type1, type2)可能拋出指定類型異常
C++11noexcept不拋出任何異常
C++11noexcept(expr)條件性異常說(shuō)明

6.2 現(xiàn)代C++異常規(guī)范

現(xiàn)代C++提供了更完善的異常處理機(jī)制,主要包括以下特性:

noexcept規(guī)范

1. 基本用法noexcept關(guān)鍵字用于指定函數(shù)是否會(huì)拋出異常

void func() noexcept;  // 保證不拋出異常
void func2() noexcept(true);  // 等價(jià)于noexcept
void func3() noexcept(false);  // 可能拋出異常

2. 條件性noexcept:可以根據(jù)表達(dá)式結(jié)果決定是否noexcept

template <typename T>
void swap(T& a, T& b) noexcept(noexcept(a.swap(b)));

3. 移動(dòng)構(gòu)造函數(shù)/賦值運(yùn)算符:標(biāo)準(zhǔn)庫(kù)容器會(huì)對(duì)noexcept移動(dòng)操作進(jìn)行優(yōu)化

class MyClass {
public:
  MyClass(MyClass&&) noexcept;  // 推薦標(biāo)記為noexcept
};

7. 標(biāo)準(zhǔn)庫(kù)異常體系

7.1 標(biāo)準(zhǔn)異常類層次結(jié)構(gòu)

  • exception - C++ Reference

  • C++標(biāo)準(zhǔn)庫(kù)也定義了一套自己的異常繼承體系,庫(kù)基類是exception,所以我們?nèi)粘懗绦?需要在主函數(shù)捕獲exception即可.要獲取異常信息,調(diào)用what函數(shù),what是一個(gè)虛函數(shù),派生類可以重寫。

7.2 常用標(biāo)準(zhǔn)異常

異常類型說(shuō)明典型應(yīng)用場(chǎng)景

std::logic_error

程序邏輯錯(cuò)誤

前置條件檢查

std::runtime_error

運(yùn)行時(shí)錯(cuò)誤

外部因素導(dǎo)致的錯(cuò)誤

std::bad_alloc

內(nèi)存分配失敗

new操作失敗

std::out_of_range

訪問(wèn)越界

容器訪問(wèn)操作

8. 實(shí)際項(xiàng)目中的異常處理策略

8.1 異常處理最佳實(shí)踐

1. 合理設(shè)計(jì)異常層次結(jié)構(gòu)

class MyProjectException : public std::exception {
    // 項(xiàng)目統(tǒng)一的異?;?
};

class NetworkException : public MyProjectException {
    // 網(wǎng)絡(luò)相關(guān)異常
};

class DatabaseException : public MyProjectException {
    // 數(shù)據(jù)庫(kù)相關(guān)異常
};

2.在適當(dāng)?shù)膶哟尾东@異常

void processRequest() {
    try {
        parseRequest();
        validateData();
        saveToDatabase();
        sendResponse();
    } catch (const DatabaseException& e) {
        // 數(shù)據(jù)庫(kù)錯(cuò)誤,可能重試或回滾
        handleDatabaseError(e);
    } catch (const NetworkException& e) {
        // 網(wǎng)絡(luò)錯(cuò)誤,可能重試
        handleNetworkError(e);
    } catch (const std::exception& e) {
        // 其他標(biāo)準(zhǔn)異常
        logError(e);
        throw; // 重新拋出
    }
}

使用異常安全的編程模式

  • 優(yōu)先使用RAII管理資源

  • 避免在析構(gòu)函數(shù)中拋出異常

  • 使用swap技法實(shí)現(xiàn)強(qiáng)異常安全保證

9. 性能考慮

9.1 異常處理的成本

異常處理的性能開(kāi)銷主要出現(xiàn)在異常拋出時(shí),而非正常流程中。具體開(kāi)銷來(lái)源包括:

  1. 棧展開(kāi)過(guò)程中的資源清理

  2. 異常對(duì)象的構(gòu)造與拷貝

  3. 異常類型匹配的查找過(guò)程

9.2 優(yōu)化建議

  1. 僅在真正異常情況下使用異常處理

  2. 避免在程序關(guān)鍵性能路徑上使用異常機(jī)制

  3. 采用移動(dòng)語(yǔ)義降低異常對(duì)象拷貝帶來(lái)的性能損耗

10. 總結(jié)

C++異常處理作為一種強(qiáng)大的錯(cuò)誤處理機(jī)制,相比傳統(tǒng)錯(cuò)誤碼方式,能提供更清晰安全的錯(cuò)誤處理方案。通過(guò)合理設(shè)計(jì)異常體系、正確應(yīng)用RAII技術(shù)并遵循最佳實(shí)踐,可以構(gòu)建出兼具健壯性和可維護(hù)性的C++應(yīng)用程序。

需要注意的是,異常處理并非適用于所有場(chǎng)景。在性能關(guān)鍵型應(yīng)用中,可能需要考慮其他錯(cuò)誤處理方案。但對(duì)于大多數(shù)應(yīng)用程序而言,合理使用異常處理能有效提升代碼質(zhì)量和可維護(hù)性。

參考資料:

  • 《Effective C++》條款8:別讓異常逃離析構(gòu)函數(shù)

  • 《C++ Primer》第5版,異常處理章節(jié)

  • cplusplus.com - Exception

到此這篇關(guān)于C++異常處理從基礎(chǔ)到應(yīng)用的文章就介紹到這了,更多相關(guān)C++異常處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • OpenCV使用BSM統(tǒng)計(jì)視頻中移動(dòng)的對(duì)象

    OpenCV使用BSM統(tǒng)計(jì)視頻中移動(dòng)的對(duì)象

    這篇文章主要為大家詳細(xì)介紹了OpenCV如何使用BackgroundSubstractor(BSM)實(shí)現(xiàn)視頻中移動(dòng)對(duì)象統(tǒng)計(jì)功能,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2023-02-02
  • c++中inline的用法分析

    c++中inline的用法分析

    本篇文章是對(duì)c++中inline的用法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
    2013-05-05
  • C++實(shí)現(xiàn)LeetCode(110.平衡二叉樹(shù))

    C++實(shí)現(xiàn)LeetCode(110.平衡二叉樹(shù))

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(110.平衡二叉樹(shù)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語(yǔ)言中g(shù)etchar函數(shù)詳解看這一篇就夠了(函數(shù)功能、使用、返回值)

    C語(yǔ)言中g(shù)etchar函數(shù)詳解看這一篇就夠了(函數(shù)功能、使用、返回值)

    getchar讀取字符的函數(shù),今天通過(guò)本文給大家介紹C語(yǔ)言中g(shù)etchar函數(shù)簡(jiǎn)介用法示例詳解,感興趣的朋友跟隨小編一起看看吧
    2023-02-02
  • C++實(shí)現(xiàn)AVL樹(shù)的示例詳解

    C++實(shí)現(xiàn)AVL樹(shù)的示例詳解

    AVL Tree 是一個(gè)「加上了額外平衡條件」的二叉搜索樹(shù),其平衡條件的建立是為了確保整棵樹(shù)的深度為O(log_2N),本文主要介紹了AVL樹(shù)的實(shí)現(xiàn),需要的可以參考一下
    2023-03-03
  • 深入了解C語(yǔ)言冒泡排序優(yōu)解

    深入了解C語(yǔ)言冒泡排序優(yōu)解

    這篇文章主要介紹了C語(yǔ)言冒泡排序法的實(shí)現(xiàn)(升序排序法),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • C++之list容器介紹及使用方式

    C++之list容器介紹及使用方式

    這篇文章主要介紹了C++之list容器介紹及使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • C語(yǔ)言之平衡二叉樹(shù)詳解

    C語(yǔ)言之平衡二叉樹(shù)詳解

    平衡二叉樹(shù)是具有平衡屬性的有序二叉樹(shù),本文主要介紹了C語(yǔ)言中的平衡二叉樹(shù),具有一定的參考價(jià)值,需要的小伙伴可以參考閱讀
    2023-04-04
  • C++?命名空間與輸入輸出操作代碼

    C++?命名空間與輸入輸出操作代碼

    C++是一種面向?qū)ο蟮挠?jì)算機(jī)程序設(shè)計(jì)語(yǔ)言,?它擴(kuò)展了C語(yǔ)言的功能,?并引入了面向?qū)ο缶幊痰母拍??如類、?繼承和多態(tài)等,C++是以C語(yǔ)言為基礎(chǔ)進(jìn)行了拓展與創(chuàng)新,C++兼容C語(yǔ)言絕大多數(shù)的語(yǔ)法,這篇文章主要介紹了C++?命名空間與輸入輸出,需要的朋友可以參考下
    2024-08-08
  • C語(yǔ)言超細(xì)致講解循環(huán)語(yǔ)句

    C語(yǔ)言超細(xì)致講解循環(huán)語(yǔ)句

    我們說(shuō)到當(dāng)滿足特定條件時(shí),就會(huì)執(zhí)行if語(yǔ)句或者switch語(yǔ)句后面的語(yǔ)句,否則不執(zhí)行,但是這只能執(zhí)行一次,在日常生活中,有些事情是需要重復(fù)去做的,C語(yǔ)句就為此引入了循環(huán)語(yǔ)句。所以今天繼續(xù)為大家分享C語(yǔ)言循環(huán)家族
    2022-05-05

最新評(píng)論