最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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)銷(xiāo)有棧展開(kāi)開(kāi)銷(xiāo)

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

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

// 拋出異常
throw exception_object;

// 捕獲異常
try {
    // 可能拋出異常的代碼
} catch (exception_type1& e) {
    // 處理特定類(lèi)型異常
} catch (exception_type2& e) {
    // 處理其他類(lèi)型異常
} 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子句但是類(lèi)型不匹配,則退出當(dāng)前函數(shù),繼續(xù) 在外層調(diào)用函數(shù)鏈中查找,上述查找的catch過(guò)程被稱(chēng)為棧展開(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)換類(lèi)型:

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

throw Derived → catch(Base&)

派生類(lèi)到基類(lèi)

3.2 繼承體系中的異常處理

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

// 異常基類(lèi)
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;
};

// 具體異常類(lèi)型
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)行分類(lèi),其中的某種異常錯(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)類(lèi)型

(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ì)元素類(lèi)型的析構(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)可能拋出指定類(lèi)型異常
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)異常類(lèi)層次結(jié)構(gòu)

  • exception - C++ Reference

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

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

異常類(lèi)型說(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)一的異?;?lèi)
};

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āo)主要出現(xiàn)在異常拋出時(shí),而非正常流程中。具體開(kāi)銷(xiāo)來(lái)源包括:

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

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

  3. 異常類(lèi)型匹配的查找過(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)文章

  • C++并查集的原理與使用方法

    C++并查集的原理與使用方法

    并查集是一種樹(shù)型的數(shù)據(jù)結(jié)構(gòu),用于處理不相交集合的合并及查詢問(wèn)題,下面這篇文章主要介紹了C++并查集原理與使用方法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-12-12
  • C語(yǔ)言中三種庫(kù)的編譯和使用方法

    C語(yǔ)言中三種庫(kù)的編譯和使用方法

    本文介紹了C語(yǔ)言自定義簡(jiǎn)易math庫(kù)的三種編譯方式:直接編譯、靜態(tài)庫(kù)(.a)和動(dòng)態(tài)庫(kù)(.so),每種方式都有詳細(xì)步驟和代碼示例,適合不同場(chǎng)景下的項(xiàng)目需求,需要的朋友可以參考下
    2026-04-04
  • C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法

    C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇C++中的多態(tài)與虛函數(shù)的內(nèi)部實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-12-12
  • C++中的六個(gè)函數(shù)

    C++中的六個(gè)函數(shù)

    本文給大家介紹了C++中的六個(gè)函數(shù),非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2018-05-05
  • C語(yǔ)言實(shí)現(xiàn)可保存的動(dòng)態(tài)通訊錄的示例代碼

    C語(yǔ)言實(shí)現(xiàn)可保存的動(dòng)態(tài)通訊錄的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何利用C語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的可保存的動(dòng)態(tài)通訊錄,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C語(yǔ)言有一定幫助,需要的可以參考一下
    2022-07-07
  • C語(yǔ)言實(shí)現(xiàn)貪吃蛇游戲代碼

    C語(yǔ)言實(shí)現(xiàn)貪吃蛇游戲代碼

    大家好,本篇文章主要講的是C語(yǔ)言實(shí)現(xiàn)貪吃蛇游戲代碼,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下
    2022-02-02
  • C++中std::for_each的使用

    C++中std::for_each的使用

    std::for_each是C++標(biāo)準(zhǔn)庫(kù)中的一個(gè)算法,用于遍歷容器并對(duì)每個(gè)元素執(zhí)行指定的操作,本文就來(lái)介紹一下C++中std::for_each的使用,感興趣的可以了解一下
    2025-04-04
  • C++ 實(shí)現(xiàn)球迷 今日頭條面試題

    C++ 實(shí)現(xiàn)球迷 今日頭條面試題

    這篇文章主要介紹了C++實(shí)現(xiàn)球迷今日頭條面試題功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-08-08
  • C語(yǔ)言實(shí)現(xiàn)鏈棧的步驟

    C語(yǔ)言實(shí)現(xiàn)鏈棧的步驟

    鏈棧是棧的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),鏈??梢杂脝捂湵淼念^插法實(shí)現(xiàn),本文主要講述了如何用c語(yǔ)言去實(shí)現(xiàn)鏈棧,感興趣的朋友可以了解下
    2021-05-05
  • C語(yǔ)言標(biāo)準(zhǔn)時(shí)間與秒單位相互轉(zhuǎn)換

    C語(yǔ)言標(biāo)準(zhǔn)時(shí)間與秒單位相互轉(zhuǎn)換

    這篇文章主要介紹了C語(yǔ)言標(biāo)準(zhǔn)時(shí)間與秒單位相互轉(zhuǎn)換,秒單位與標(biāo)準(zhǔn)時(shí)間的轉(zhuǎn)換方式,這份代碼一般用在嵌入式單片機(jī)里比較多,比如:設(shè)置RTC時(shí)鐘的時(shí)間,從RTC里讀取秒單位時(shí)間后,需要轉(zhuǎn)換成標(biāo)準(zhǔn)時(shí)間顯示。下文分享需要的小伙伴可以參考一下
    2022-05-05

最新評(píng)論

新河县| 桂林市| 泰宁县| 泰来县| 渭源县| 浏阳市| 姜堰市| 巴南区| 隆化县| 宁国市| 贺州市| 孟连| 额济纳旗| 梧州市| 贵阳市| 乐东| 隆尧县| 徐汇区| 吉林省| 蛟河市| 襄汾县| 樟树市| 江都市| 章丘市| 海伦市| 大港区| 凤翔县| 邵阳县| 昌邑市| 元氏县| 富蕴县| 罗山县| 长春市| 北海市| 保德县| 汶川县| 伊金霍洛旗| 抚州市| 深圳市| 印江| 福州市|