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

C++的異常處理詳解

 更新時間:2026年05月19日 09:03:53   作者:程序員小青蛙  
文章主要介紹了C++異常處理的概念、使用方法及優(yōu)缺點(diǎn),文章還討論了異常的規(guī)范使用,包括自定義異常體系和C++標(biāo)準(zhǔn)庫的異常體系,并強(qiáng)調(diào)了異常在現(xiàn)代編程中的重要性,感興趣的朋友跟隨小編一起看看吧

前言

C語言中處理錯誤的方式:
1.終止程序,如assert,不方便,用戶不接受,
2.返回錯誤碼,缺點(diǎn):需要程序員自己去找
3.C標(biāo)準(zhǔn)庫中也有setjmp和longjmp,不過不常用,

基本都是使用錯誤碼返回的方式處理,除非嚴(yán)重錯誤才會使用終止程序

下面是C++的異常處理

一、C++異常的概念

當(dāng)一個函數(shù)發(fā)生錯誤時可以拋出異常,讓函數(shù)直接或間接的調(diào)用來處理這個錯誤

1.throw:當(dāng)問題出現(xiàn)時,程序會拋出一個異常,
2.catch:在想要處理問題的地方,通過異常程序處理程序捕獲異常,catch關(guān)鍵字用于捕獲異常,可以有多個catch進(jìn)行捕獲。
3.try:try塊中的代碼標(biāo)識將被激活的特定異常,他的后面通常跟著一個或多個catch塊。

如果有一個塊發(fā)生異常,捕獲異常的方法就是使用try和catch關(guān)鍵字。try塊中放可能拋出異常的代碼,try中的代碼為保護(hù)代碼,

try
{
  //保護(hù)的標(biāo)識代碼
}
catch(exceptionName e1)
{
  //catch塊
}
catch(exceptionName e2)
{
  //catch塊
}

二、異常的使用

1.異常的拋出和捕獲

異常的拋出和匹配原則:
1.異常是通過拋出對象而引發(fā)的,該對象的類型決定了應(yīng)該激活哪個catch的處理代碼。
2.被選中的處理代碼是調(diào)用鏈中與該對象類型匹配且離拋出異常位置最近的那一個。
3.拋出異常對象后,會生成一個異常對象的拷貝,因為拋出的異常對象可能是一個臨時對象,所以會生成一個拷貝對象,這個拷貝的臨時對象會在被catch以后銷毀。(這里的處理類似于函數(shù)的傳值返回)
4. catch(...)可以捕獲任意類型的異常,問題是不知道異常錯誤是什么。(無語型)
5.實(shí)際中拋出和捕獲的匹配原則有個例外,并不都是類型完全匹配,可以拋出的派生類對象,使用基類捕獲,這個在實(shí)際中非常實(shí)用

在函數(shù)調(diào)用鏈中異常棧展開匹配原則:
1.首先檢查throw本身是否在try塊內(nèi)部,如果是再查找匹配的catch語句。如果有匹配的,則調(diào)到catch的地方進(jìn)行處理。
2.沒有匹配的catch則退出當(dāng)前函數(shù)棧,繼續(xù)在調(diào)用函數(shù)的棧中進(jìn)行查找匹配的catch。
3.如果到達(dá)main函數(shù)的棧,依舊沒有匹配的,則終止程序。上述這個沿著調(diào)用鏈查找匹配的catch子句的過程稱為棧展開。所以實(shí)際中我們最后都要加一個catch(...)捕獲任意類型的異常,否則當(dāng)有異常沒捕獲,程序就會直接終止。
4.找到匹配的catch子句并處理以后,會繼續(xù)沿著catch子句后面繼續(xù)執(zhí)行。

func1()
{
   throw e;
}
func2()
{
   func1();
}
func3()
{
   func2();
}
int main()
{
  func3();
}

有三個函數(shù)
funcl、func2、func3,都在其中。
在func2中調(diào)用
在funcl、func3中調(diào)用
在func2和main中調(diào)用func3,并在func1中拋出異常/錯誤
出現(xiàn)異常時,在main中使用catch語句捕獲

棧的展開過程如下:
首先檢查`throw`本身是否存在于`try`語句中。
在塊的內(nèi)部,如果需要繼續(xù)查找匹配的內(nèi)容的話
catch語句。如果有匹配項,則執(zhí)行相應(yīng)處理。
如果沒有,則退出當(dāng)前函數(shù)棧,繼續(xù)執(zhí)行后續(xù)操作。
在調(diào)用函數(shù)的棧中進(jìn)行查找,不斷重復(fù)此過程。
重復(fù)上述過程,若到達(dá)main函數(shù)的棧,
如果棧中仍然沒有匹配項,則終止程序。

double Division(int a, int b)
{
 //當(dāng)b == 0時拋出異常
 if (b == 0)
 throw "Division by zero condition!";
 else
 return ((double)a / (double)b);
}
void Func()
{
 int len, time;
 cin >> len >> time;
 cout << Division(len, time) << endl;
}
int main()
{
 try
 {
 Func();
 }
 catch (const char* errmsg){
 cout << errmsg << endl;
 }
 catch(...){
 cout<<"unkown exception"<<endl;
 }
return 0;
}

2.異常的重新拋出

有可能單個的catch不能完全處理一個異常,在進(jìn)行一些校正處理以后,希望再交給更外層的調(diào)用鏈函數(shù)來處理,catch則可以通過重新拋出將異常傳遞給更上層的函數(shù)進(jìn)行處理。

double Division(int a, int b)
{
//當(dāng)b == 0時拋出異常
if (b == 0)
{
throw "Division by zero condition!";
}
return (double)a / (double)b;
}
void Func()
{
//這里可以看到如果發(fā)生除0錯誤拋出異常,另外下面的array沒有得到釋放。
//所以這里捕獲異常后并不處理異常,異常還是交給外面處理,這里捕獲了再
//重新拋出去。
int* array = new int[10];
try {
int len, time;
cin >> len >> time;
cout << Division(len, time) << endl;
}
 catch (...)
{
cout << "delete []" << array << endl;
delete[] array;
throw;
}
// ...
cout << "delete []" << array << endl;
delete[] array;
}
int main()
{
try
{
Func();
}
catch (const char* errmsg)
{
cout << errmsg << endl;
}
return 0;
}

3.異常安全

構(gòu)造函數(shù)完成對象的構(gòu)造和初始化,最好不要在構(gòu)造函數(shù)中拋出異常,否則可能導(dǎo)致對象不完整或沒有完全初始化
析構(gòu)函數(shù)主要完成資源的清理,最好不要在析構(gòu)函數(shù)內(nèi)拋出異常,否則可能導(dǎo)致資源泄漏(內(nèi)存泄漏、句柄未關(guān)閉等)
C++中異常經(jīng)常會導(dǎo)致資源泄漏的問題,比如在new和delete中拋出了異常,導(dǎo)致內(nèi)存泄漏,在lock和unlock之間拋出了異常導(dǎo)致死鎖,C++經(jīng)常使用RAII來解決以上問題,關(guān)于RAII看智能指針。

4.異常規(guī)范

1.異常規(guī)格說明的目的是為了讓函數(shù)使用者知道該函數(shù)可能拋出的異常有哪些??梢栽诤瘮?shù)的后面接throw(類型),列出這個函數(shù)可能拋擲的所有異常類型。
2.函數(shù)的后面接throw(),表示函數(shù)不拋異常。
3.若無異常接口聲明,則此函數(shù)可以拋擲任何類型的異常。

//這里表示這個函數(shù)會拋出A/B/C/D中的某種類型的異常
void fun() throw(A,B,C,D);
//這里表示這個函數(shù)只會拋出bad_alloc的異常
void* operator new (std::size_t size) throw (std::bad_alloc);
//這里表示這個函數(shù)不會拋出異常
void* operator new (std::size_t size, void* ptr) throw();

5.自定義異常體系

實(shí)際使用中很多公司都會自定義自己的異常體系進(jìn)行規(guī)范的異常管理,因為一個項目中如果大家隨意拋異常,那么外層的調(diào)用者基本就沒辦法玩了,所以實(shí)際中都會定義一套繼承的規(guī)范體系。這樣大家拋出的都是繼承的派生類對象,捕獲一個基類就可以了。

//服務(wù)器開發(fā)中通常使用的異常繼承體系
class Exception
{
protected:
string _errmsg;
int _id;
//list<StackInfo> _traceStack;
// ...
};
class SqlException : public Exception
{};
class CacheException : public Exception
{};
class HttpServerException : public Exception
{};
int main()
{
try{
// server.Start();
//拋出對象都是派生類對象
}
catch (const Exception& e) //這里捕獲父類對象就可以
{}
catch (...)
{
cout << "Unkown Exception" << endl;
}
return 0;
}

6.C++標(biāo)準(zhǔn)庫的異常體系

C++提供了一系列標(biāo)準(zhǔn)的異常,定義在中,我們可以在程序中使用這些標(biāo)準(zhǔn)的異常。它們是以父子類層次結(jié)構(gòu)組織起來的,如下所示:

std:exception
std:bad_alloc
std:bad_cat
std:bad_typeid
std:bad_exception
std:logic_error

std:domain_error

std:invalid_argument

std:length_error

std:out_of_range

std:runtime_error

std:overflow_error

std:range_error

std:underflow_error

功能::::

說明:實(shí)際中我們可以可以去繼承exception類實(shí)現(xiàn)自己的異常類。但是實(shí)際中很多公司像上面一樣自己定義一套異常繼承體系。因為C++標(biāo)準(zhǔn)庫設(shè)計的不夠好用。

int main()
{
try{
 vector<int> v(10, 5);
 //這里如果系統(tǒng)內(nèi)存不夠也會拋異常
 v.reserve(1000000000);
 //這里越界會拋異常
 v.at(10) = 100;
}
 catch (const exception& e) //這里捕獲父類對象就可以
{
 cout << e.what() << endl;
}
catch (...)
{
 cout << "Unkown Exception" << endl;
}
return 0;
}

7.異常的優(yōu)缺點(diǎn)

C++異常的優(yōu)點(diǎn):
1.異常對象定義好了,相比錯誤碼的方式可以清晰準(zhǔn)確的展示出錯誤的各種信息,甚至可以包含堆棧調(diào)用的信息,這樣可以幫助更好的定位程序的bug。
2.返回錯誤碼的傳統(tǒng)方式有個很大的問題就是,在函數(shù)調(diào)用鏈中,深層的函數(shù)返回了錯誤,那么我們得層層返回錯誤,最外層才能拿到錯誤,具體看下面的詳細(xì)解釋。

// 1.下面這段偽代碼我們可以看到ConnnectSql中出錯了,先返回給ServerStart,ServerStart再
//返回給main函數(shù),main函數(shù)再針對問題處理具體的錯誤。
// 2.如果是異常體系,不管是ConnnectSql還是ServerStart及調(diào)用函數(shù)出錯,都不用檢查,因為拋
//出的異常異常會直接跳到main函數(shù)中catch捕獲的地方,main函數(shù)直接處理錯誤。
int ConnnectSql()
{
 //用戶名密碼錯誤
 if (...)
 return 1;
 //權(quán)限不足
 if (...)
 return 2;
}
int ServerStart() {
 if (int ret = ConnnectSql() < 0)
 return ret;
 int fd = socket()
 if(fd < 0)
 return errno;
 }
int main()
{
 if(ServerStart()<0)
 ...
return 0;
}

3.很多的第三方庫都包含異常,比如boost、gtest、gmock等等常用的庫,那么我們使用它們也需要使用異常。
4.很多測試框架都使用異常,這樣能更好的使用單元測試等進(jìn)行白盒的測試。
5.部分函數(shù)使用異常更好處理,比如構(gòu)造函數(shù)沒有返回值,不方便使用錯誤碼方式處理。比如T&
operator這樣的函數(shù),如果pos越界了只能使用異?;蛘呓K止程序處理,沒辦法通過返回值表示錯誤。

C++異常的缺點(diǎn):

1.異常會導(dǎo)致程序的執(zhí)行流亂跳,并且非常的混亂,并且是運(yùn)行時出錯拋異常就會亂跳。這會導(dǎo)致我們跟蹤調(diào)試時以及分析程序時,比較困難。
2.異常會有一些性能的開銷。當(dāng)然在現(xiàn)代硬件速度很快的情況下,這個影響基本忽略不計。
3. C++沒有垃圾回收機(jī)制,資源需要自己管理。有了異常非常容易導(dǎo)致內(nèi)存泄漏、死鎖等異常安全問題。這個需要使用RAII來處理資源的管理問題。學(xué)習(xí)成本較高。
4. C++標(biāo)準(zhǔn)庫的異常體系定義得不好,導(dǎo)致大家各自定義各自的異常體系,非常的混亂。
5.異常盡量規(guī)范使用,否則后果不堪設(shè)想,隨意拋異常,外層捕獲的用戶苦不堪言。所以異常規(guī)范有兩點(diǎn):一、拋出異常類型都繼承自一個基類。二、函數(shù)是否拋異常、拋什么異常,都使用func()throw();的方式規(guī)范化。

總結(jié)

異??傮w而言,利大于弊,所以工程中我們還是鼓勵使用異常的。另外OO的語言基本都是用異常處理錯誤,這也可以看出這是大勢所趨。

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

相關(guān)文章

  • FFmpeg實(shí)戰(zhàn)之分離出PCM數(shù)據(jù)

    FFmpeg實(shí)戰(zhàn)之分離出PCM數(shù)據(jù)

    PCM(Pulse?Code?Modulation,脈沖編碼調(diào)制)音頻數(shù)據(jù)是未經(jīng)壓縮的音頻采樣數(shù)據(jù)裸流,它是由模擬信號經(jīng)過采樣、量化、編碼轉(zhuǎn)換成的標(biāo)準(zhǔn)數(shù)字音頻數(shù)據(jù)。本文將通過FFmpeg實(shí)現(xiàn)分離PCM數(shù)據(jù),感興趣的可以了解一下
    2023-02-02
  • 餐館點(diǎn)菜系統(tǒng)C語言源代碼

    餐館點(diǎn)菜系統(tǒng)C語言源代碼

    這篇文章主要為大家詳細(xì)介紹了餐館點(diǎn)菜系統(tǒng)C語言源代碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • C++17之std::any的具體使用

    C++17之std::any的具體使用

    本文主要介紹了C++17之std::any的具體使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C語言實(shí)現(xiàn)的猜數(shù)字小游戲

    C語言實(shí)現(xiàn)的猜數(shù)字小游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)的猜數(shù)字小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • C語言詳解如何實(shí)現(xiàn)順序棧

    C語言詳解如何實(shí)現(xiàn)順序棧

    順序棧,就是用一組地址連續(xù)的存儲單元來存放棧元素,然后用一個棧結(jié)構(gòu)去維護(hù)一個棧。在C中,可用動態(tài)開辟的數(shù)組去表示,維護(hù)的棧結(jié)構(gòu)需要有一個棧底和一個棧頂指針
    2022-04-04
  • C++中神奇的tuple詳解使用技巧及實(shí)例解析

    C++中神奇的tuple詳解使用技巧及實(shí)例解析

    C++11標(biāo)準(zhǔn)新引入了一種類模板,命名為 tuple(中文可直譯為元組),下面這篇文章主要給大家介紹了關(guān)于C++中神奇的tuple詳解使用技巧及實(shí)例解析的相關(guān)資料,需要的朋友可以參考下
    2024-01-01
  • C++進(jìn)一步認(rèn)識類與對象

    C++進(jìn)一步認(rèn)識類與對象

    類是創(chuàng)建對象的模板,一個類可以創(chuàng)建多個對象,每個對象都是類類型的一個變量;創(chuàng)建對象的過程也叫類的實(shí)例化。每個對象都是類的一個具體實(shí)例(Instance),擁有類的成員變量和成員函數(shù)
    2021-10-10
  • C++基于Floyd算法實(shí)現(xiàn)校園導(dǎo)航系統(tǒng)

    C++基于Floyd算法實(shí)現(xiàn)校園導(dǎo)航系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C++基于Floyd算法實(shí)現(xiàn)校園導(dǎo)航系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • C++內(nèi)存序的操作方法

    C++內(nèi)存序的操作方法

    在C++中,內(nèi)存序(Memory Order)是一個非常重要的概念,特別是在多線程編程中,本文通過實(shí)例代碼介紹C++內(nèi)存序的相關(guān)知識,感興趣的朋友一起看看吧
    2025-11-11
  • 一文帶你了解C++中queue的使用

    一文帶你了解C++中queue的使用

    C++中的queue是一種容器,用于在FIFO(先進(jìn)先出)原則下存儲和管理元素。本篇文章將深入探討C++中的queue,包括它的定義、使用、原理和示例,感興趣的可以了解一下
    2023-04-04

最新評論

施甸县| 湖北省| 大安市| 长乐市| 土默特左旗| 周至县| 榆社县| 三都| 塔城市| 大新县| 印江| 乐都县| 阿瓦提县| 册亨县| 邵阳县| 淳化县| 海安县| 九龙城区| 宁明县| 德昌县| 牡丹江市| 浠水县| 巴里| 济阳县| 盐源县| 明星| 安多县| 宾川县| 大冶市| 汉源县| 万年县| 中山市| 鸡泽县| 白玉县| 保靖县| 望城县| 新乐市| 渑池县| 习水县| 建瓯市| 思茅市|