日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

C++异常处理,Error,C和C++ 解决容错,栈自旋,Standard Exception【C++异常处理】(60)

發(fā)布時間:2025/3/20 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++异常处理,Error,C和C++ 解决容错,栈自旋,Standard Exception【C++异常处理】(60) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

  • 異常處理
  • Error
  • C Error
  • C和C++ 解決容錯
  • 異常定義
    • 語法格式
    • 使用條例
    • 異常流程測試
  • 棧自旋
    • unwinding
    • RAII in Exception
  • Standard Exception
    • 異常自定義與拋出
    • 標準異常
      • 標準異常分類
      • 標準異常使用

異常處理

Error

Error 譯為錯誤,常見的 Error 有編譯時 Error 和運行時 Error。運行時的 Error 又分為不可預(yù)料的邏輯錯誤和可以預(yù)料的運行異常。

可以預(yù)料的運行異常,常見的有,I/0,文件打開失敗,動態(tài)內(nèi)存分配失敗,越界訪問等。

C Error

C 語言中錯誤的處理,通常采用返回值的方式或是置位全局變量的方式。這就存在兩個問題。如果返回值正是我們需要的數(shù)據(jù),且返回數(shù)據(jù)同出錯數(shù)據(jù) 容錯性不高。全局變量,在多線程中易引發(fā)競爭。而且,當錯誤發(fā)生時,上級函數(shù)要出錯處理,層層上報,造成過多的出錯處理代碼,且傳遞的效率低下。

C++ 通過異常實現(xiàn)了返回與錯誤的處理的分離。

C和C++ 解決容錯

#include <iostream> #include <cmath> using namespace std; double triangleArea(double x, double y, double z) {double area;double s = (x + y + z) / 2;if (x + y > z && y + z > x && x + z > y) //邏輯代碼area = sqrt(s * (s - x) * (s - y) * (s - z));else //錯誤接口return -1.0;return area; } int main() {int a, b, c;float area;while (1){cin >> a >> b >> c;if (a > 0 && b > 0 && c > 0){area = triangleArea(a, b, c);if (area == -1.0)cout << "輸入的三角形不合法" << endl;elsecout << "Area:" << area << endl;}}return 0; }

運行結(jié)果為:

上面函數(shù)triangleArea中把正常邏輯代碼和錯誤碼整合到一個函數(shù)接口進行返回。

那么C++里面對于錯誤就會單獨處理。

#include <iostream> #include <cmath> using namespace std; double triangleArea(double x, double y, double z) {double area;double s = (x + y + z) / 2;if (x + y > z && y + z > x && x + z > y)area = sqrt(s * (s - x) * (s - y) * (s - z));elsethrow - 1.0;return area; } int main() {int a, b, c;float area;try {while (1){cin >> a >> b >> c;if (a > 0 && b > 0 && c > 0){area = triangleArea(a, b, c);cout << "Area:" << area << endl;}}}catch (double e){cout << "return " << e << endl;cout << "輸入的三角形不合法" << endl;}return 0; }

運行結(jié)果為:

上面代碼中,如果出現(xiàn)一場,就拋出異常。不和功能代碼進行整合。把錯誤處理和返回分離。

分析:

1,把可能發(fā)生異常的語句放在 try 語句聲當中。try 不影響原有語句的執(zhí)行流程。

2,若未發(fā)生異常,catch 子語句并不起作用。程序會流轉(zhuǎn)到 catch 子句的后面執(zhí)行。

3,若 try 塊中發(fā)生異常,則通過 throw 拋出異常。throw 拋出異常后,程序立即離開本函數(shù),轉(zhuǎn)到上一級函數(shù)。所以 triangleArea 函數(shù)中的 return 語句不會執(zhí)行。

圖解說明:

4,throw 拋出數(shù)據(jù),類型不限。既可以是基本數(shù)據(jù)類型,也可以是構(gòu)造數(shù)據(jù)類型。

5,程序流轉(zhuǎn)到 main 函數(shù)以后,try 語句塊中拋出進行匹配。匹配成功,執(zhí)行 catch語句,catch 語句執(zhí)行完畢后。繼續(xù)執(zhí)行后面的語句。

6,如無匹配,系統(tǒng)調(diào)用 terminate 終止程序。

#include <iostream> #include <cmath> using namespace std; double triangleArea(double x, double y, double z) {double area;double s = (x + y + z) / 2;if (x + y > z && y + z > x && x + z > y)area = sqrt(s * (s - x) * (s - y) * (s - z));elsethrow - 1;return area; } int main() {int a, b, c;float area;try {while (1){cin >> a >> b >> c;if (a > 0 && b > 0 && c > 0){area = triangleArea(a, b, c);cout << "Area:" << area << endl;}}}catch (double e){cout << "return " << e << endl;cout << "輸入的三角形不合法" << endl;}return 0; }

上面代碼異常返回值為1,但是catch參數(shù)類型為double 那么直接會出現(xiàn)問題:

運行結(jié)果:

我們可以換一種寫法,catch參數(shù)為…

#include <iostream> #include <cmath> using namespace std; double triangleArea(double x, double y, double z) {double area;double s = (x + y + z) / 2;if (x + y > z && y + z > x && x + z > y)area = sqrt(s * (s - x) * (s - y) * (s - z));elsethrow - 1;return area; } int main() {int a, b, c;float area;try {while (1){cin >> a >> b >> c;if (a > 0 && b > 0 && c > 0){area = triangleArea(a, b, c);cout << "Area:" << area << endl;}}}catch (double e){cout << "return " << e << endl;cout << "輸入的三角形不合法" << endl;}catch (...){cout << "捕獲到了未知異常" << endl;}return 0; }

運行結(jié)果為:

如果沒有任何捕獲,系統(tǒng)將會殺死程序運行。

異常定義

語法格式

try {被檢查可能拋出異常的語句 } catch(異常信息類型 [變量名]) {進行異常處理的語句 }

使用條例

1,被檢語句必須放在 try 塊中,否則不起作用。

2,try catch 中花括號不可省。

3,一個 try-catch 結(jié)構(gòu)中,只能有一個 try 塊,catch 塊卻可以有多個。以便與不同的類型信息匹配。

try{} catch(double){} catch(int){} catch(char){} catch(float){}

4,throw 拋出的類型,既可以是系統(tǒng)預(yù)定義的標準類型也可以是自定義類型。從拋出到 catch 是一次復(fù)制拷貝的過程。如果有自定義類型,要考慮自定義類型的拷貝問題。

5,異常匹配,不作類型轉(zhuǎn)化。如果 catch 語句沒有匹配異常類型信息,就可以用(…)表示可以捕獲任何異常類型的信息。

catch(...) { cout<<"catch a unknow exception"<<endl; }

6.try-catch 結(jié)構(gòu)可以與 throw 在同一個函數(shù)中,也可以不在同一個函數(shù)中,throw拋出異常后,先在本函數(shù)內(nèi)尋找與之匹配的 catch 塊,找不到與之匹配的就轉(zhuǎn)到上一層,如果上一層也沒有,則轉(zhuǎn)到更上一層的 catch 塊。如果最終找不到與之匹配的 catch 塊,系統(tǒng)則會調(diào)有系統(tǒng)函數(shù) terminate 使程序終止。

層級管理中,最好的處理方式就是在本層內(nèi)解決,一旦出現(xiàn)異常層層上拋,工程量很大的時候就會打破層級管理的設(shè)計,所以不常使用。

異常流程測試

在中間環(huán)節(jié),來測試異常的流程。

#include <iostream>using namespace std;//通過聲明的方式,告知,調(diào)用方,如何處理 void func() throw(char) {throw 'a'; } //什么都沒有寫的情況-> 上拋 //寫點什么,處理自己可以處理的部分 ,若無匹配上拋 void foo() {try{func();}catch (int i){cout << "foo() catch " << i << endl;}catch (...) //若無匹配,寫日志上拋{cout << "log throw up" << endl;throw;} } int main() {try {foo();}catch (int i) {cout << "main() catch int " << i << endl;}catch (double i) {cout << "main() catch double " << i << endl;}return 0; }

運行結(jié)果為:

如果拋出double類型,并且有double類型異常接受。

#include <iostream>using namespace std;//通過聲明的方式,告知,調(diào)用方,如何處理 void func() throw(double) {throw 1.1; } //什么都沒有寫的情況-> 上拋 //寫點什么,處理自己可以處理的部分 ,若無匹配上拋 void foo() {try{func();}catch (int i){cout << "foo() catch " << i << endl;}catch (...) //若無匹配,寫日志上拋{cout << "log throw up" << endl;throw;} } int main() {try {foo();}catch (int i) {cout << "main() catch int " << i << endl;}catch (double i) {cout << "main() catch double " << i << endl;}return 0; }

運行結(jié)果為:

拋出異常聲明
(1)一個不拋擲任何類型異常的函數(shù)可以聲明為:
void func() throw(); //推薦使用

(2)如果在函數(shù)聲明中沒有包含異常接口聲明,則函數(shù)可以拋擲任何類型的異常,
例如:
void func(); //不推薦

(3)為了加強程序的可讀性,可以在函數(shù)聲明中列出可能拋出的所有異常類型。
例如:
void func() throw (A, B, C , D); //這個函數(shù) func()能夠且只能拋出類型 A B C D及其子類型的異常。

(4)如果一個函數(shù)拋出了它的異常接口聲明所不允許拋出的異常,該函數(shù)默認行為調(diào)用 terminate 函數(shù)中止程序。

代碼說明:

#include <iostream> using namespace std; class up {}; class down {}; void g() {throw 1; } //異常規(guī)格說明,f 函數(shù)只能拋出 up 和 down 類型的異常 void f(int i)throw(up, down) {switch (i) {case 1: throw up();case 2: throw down();}g(); } int main() {try {// f(1);f(4);}catch (...){cout << "捕獲一個未知異常" << endl;}return 0; }

運行結(jié)果為:

棧自旋

unwinding

異常被拋出后,從進入 try 塊起,到異常被拋擲前,這期間在棧上的構(gòu)造的所有對象,都會被自動析構(gòu)。析構(gòu)的順序與構(gòu)造的順序相反。這一過程稱為棧的解旋(unwinding)。

#include <iostream> #include <memory> using namespace std; class A { public:A(){cout << "A constructor" << endl;}~A(){cout << "~A destructor" << endl;} }; int divide(int x, int y) {A a;if (y == 0)throw('a');return x / y; } void myDivide(int x, int y) {divide(x, y); } int main() {try {myDivide(4, 0);}catch (int x) {cout << "x" << endl;cout << x << endl;}catch (double y) {cout << "y" << endl;cout << y << endl;}catch (...){cout << "no x, no y" << endl;}return 0; }

運行結(jié)果為:

我們可以看到棧上發(fā)生了析構(gòu)。

我們對于代碼進行修改:

#include <iostream> #include <memory> using namespace std; class A { public:A(){cout << "A constructor" << endl;}~A(){cout << "~A destructor" << endl;} }; int divide(int x, int y) {A *p = new A;if (y == 0)throw('a');return x / y; } void myDivide(int x, int y) {divide(x, y); } int main() {try {myDivide(4, 0);}catch (int x) {cout << "x" << endl;cout << x << endl;}catch (double y) {cout << "y" << endl;cout << y << endl;}catch (...){cout << "no x, no y" << endl;}return 0; }

運行結(jié)果為:

我們可以看到,如果是堆上的內(nèi)存不會發(fā)生析構(gòu),那么就會導(dǎo)致內(nèi)存泄露。
我們對于代碼進行修改:

#include <iostream> #include <memory> using namespace std; class A { public:A(){cout << "A constructor" << endl;}~A(){cout << "~A destructor" << endl;} }; int divide(int x, int y) {A *p = new A;auto_ptr<A> pa(new A); //RAII 資源獲取(new)及初始化(構(gòu)造)if (y == 0)throw('a');return x / y; } void myDivide(int x, int y) {divide(x, y); } int main() {try {myDivide(4, 0);}catch (int x) {cout << "x" << endl;cout << x << endl;}catch (double y) {cout << "y" << endl;cout << y << endl;}catch (...){cout << "no x, no y" << endl;}return 0; }

運行結(jié)果為:

棧自旋也就是說,在拋出異常的時候要清棧,那么new的資源必須經(jīng)過RAII包裹,否則就會泄露。

RAII in Exception

而堆上的空間,則會泄漏。利用遵循 RAII 思想的智能指針來解決。

Standard Exception

異常自定義與拋出

MyExcept

如果導(dǎo)致異常的因素有5個,我們不能拋出5次,所以就打包為一個類。

#include <iostream>using namespace std;class MyException { public:MyException(){cout << "MyException constructor" << endl;}MyException(const MyException&){cout << "MyException copy constructor" << endl;}~MyException(){cout << "~MyException destructor" << endl;} }; int divide(int x, int y) {if (y == 0)throw(MyException()); //拋出類return x / y; } void myDivide(int x, int y) { divide(x, y); } int main() {try {myDivide(4, 0);}catch (const MyException& a) { //& cout << "catch self define myexception" << endl;}return 0; }

運行結(jié)果為:

我們可以看到一次構(gòu)造和一次析構(gòu)。

標準異常

標準異常分類

標準異常使用

#include <iostream> using namespace std; int main() {double* p;for (int i = 0; i < 1000; i++){p = new double[900000000];}return 0; }

上面代碼會編譯會出現(xiàn)錯誤:

我們對于異常進行處理:

#include <iostream> using namespace std; int main() {try {double* p;for (int i = 0; i < 1000; i++){p = new double[900000];}}catch (std::bad_alloc & e) {cout << e.what() << endl;exit(-1);}return 0; }

運行結(jié)果為:

總結(jié)

以上是生活随笔為你收集整理的C++异常处理,Error,C和C++ 解决容错,栈自旋,Standard Exception【C++异常处理】(60)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。