C++ 異常機制(上)

1、概念

異常:存在於運行時的反常行爲,這些行爲超過了函數的正常的功能範圍。ios

異常處理:處理程序中的錯誤,異常處理機制爲程序中異常檢測和異常處理這兩部分的協做提供支持。c++

在C++中,異常處理包括:ide

  • throw表達式,表示遇到了沒法處理的問題
  • try語句塊,處理異常;以關鍵字try開始,一個或多個catch結束
  • 一套異常類,用於在throw表達式和相關的catch子句之間傳遞異常的信息。

2、異常的好處

  1. 整性返回值沒有語義信息,而異常包含語義信息,有時從類名即可看出。
  2. 異常做爲一個類,有本身的成員,能夠傳遞足夠的信息。
  3. 函數的返回值能夠忽略,異常不能夠忽略,能夠使程序更加健壯。

3、基本語法

#include<iostream>
using namespace std;

//異常基本語法

int divide(int x ,int y){
	if (y == 0){
		throw y;  //拋異常
	}
	return x / y;
}
void test01(){

	//試着去捕獲異常
	try{
		divide(10, 0);
	}
	catch (int e){ //異常時根據類型進行匹配
		cout << "除數爲" << e << "!" << endl;
	}	
}


void CallDivide(int x,int y){	
	divide(x, y);
}
//a() -> b() - >c()  -> d(),d()中的異常一層層向上拋到terminate的標準庫函數,直處處理爲止

void test02(){	
	try{
		CallDivide(10,0);
	}
	catch (int e){
		cout << "除數爲" << e << endl;
	}
}

//C++異常機制跨函數
//異常必須處理,若是異常拋到頂層尚未處理,程序便會掛掉。
int main(){
	
	//test01();
	test02();
}

4、棧解旋

異常被拋出後,從進入try塊起,到異常被拋前,這期間在棧上構造的全部對象,都會被自動析構,析構的順序與構造的順序相反,這一過程即爲棧解旋函數

構造函數沒有返回類型,沒法經過返回值來報告運行狀態,因此經過異常機制來解決構造函數的出錯問題。this

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class Person{
public:
	Person(){
		cout << "對象構建!" << endl;
	}
	~Person(){
		cout << "對象析構!" << endl;
	}
};

int divide(int x,int y){
	Person p1, p2;
	if (y == 0){
		throw y;
	}
	return  x / y;
}

void test01(){

	try{
		divide(10,0);//棧解旋
	}
	catch (int e){
		cout << "異常捕獲!" << endl;
	}
}

int main(void)
{
	test01();
	return 0;
}
/*
結果:
    對象構建!
	對象構建!
	對象析構!
	對象析構!
	異常捕獲!
*/

5、異常接口聲明

  1. 爲了增強程序的可讀性,能夠在函數聲明中列出可能拋出的全部異常類型,例如:
    void func() throw (A, B, C , D); //這個函數func()可以且只能拋出類型A B C D及其子類型的異常。
  2. 若是在函數聲明中沒有包含異常接口聲明,則次函數能夠拋擲任何類型的異常,例如:
    void func();
  3. 一個不拋擲任何類型異常的函數能夠聲明爲:
    void func() throw();
  4. 若是一個函數拋出了它的異常接口聲明所不容許拋出的異常,unexpected函數會被調用,該函數默認行爲調用terminate函數停止程序
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

//這個函數只能拋出int float char三種類型異常,拋出其餘的就報錯
void func() throw(int,float,char){
	throw "abc";
}

//不能拋出任何異常
void func02() throw(){
	throw -1;
}

//能夠拋出任何類型異常
void func03(){
}

int main(void)
{
	try{
		func();
	}
	catch (char* str){
		cout << str << endl;
	}
	catch (int e){
		cout << "異常!" << endl;
	}
	catch (...){ //捕獲全部異常
		cout << "未知類型異常!" << endl;
	}
	return 0;
}

//結果: 未知類型異常!

6、異常對象的內存模型

throw的異常是有類型的,能夠是數字、字符串、類對象,catch需嚴格匹配異常類型。spa

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

void func01(){
	throw 1; //拋出int類型異常
}

void func02(){
	throw "exception";
}

class MyException{
public:
	MyException(const char* str){
		error = new char[strlen(str)+1];
		strcpy(error, str);
	}
	
	MyException(const MyException& ex){
		this->error = new char[strlen(ex.error) + 1];
		strcpy(this->error,ex.error);
	}
	MyException& operator=(const MyException& ex){
		if (this->error != NULL){
			delete[] this->error;
			this->error = NULL;
		}
		this->error = new char[strlen(ex.error) + 1];
		strcpy(this->error, ex.error);
	}
	
	void what(){
		cout << error << endl;
	}
	~MyException(){
		if (error != NULL){
			delete[] error;
		}
	}
public:
	char* error;
};

void fun03(){
	throw MyException("我剛寫異常!");
}

void test01(){	
	try{
		func01();
	}
	catch (int e){
		cout << "int 異常捕獲!" << endl;
	}
//----------------------------------
	try{
		func02();
	}
	catch (const char* e){
		cout << "const char* 異常捕獲!" << endl;
	}
//----------------------------------
	try{
		fun03();
	}
	catch (MyException e){
		e.what();
	}
}
int main(void){	
	test01();
	return 0;
}
/*
int 異常捕獲!
const char* 異常捕獲!
我剛寫異常!
*/

7、異常對象的生命週期

  1. catch裏能夠用普通類型元素,引用,指針去接
  2. 普通元素去接,異常對象catch處理完以後就析構
  3. 引用的話,不用調用拷貝構造,異常對象catch處理完以後就析構
  4. 指針接,throw的時候必須用new才能接的到,catch裏必需要delete
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class MyException {
public:
	MyException() {
		cout << "構造函數!" << endl;
	}
	MyException(const MyException& ex) {
		cout << "拷貝構造!" << endl;
	}
	~MyException() {
		cout << "析構函數!" << endl;
	}
};
void func() {
	//throw &(MyException()); //建立匿名對象,調用構造
    //throw new MyException();//用指針接
	throw MyException();
}
void test01();
int main(void) {
	test01();
	return 0;
}

/*
void test01();{
	try {
		func();
	}
	catch (MyException e) {
		cout << "異常捕獲!" << endl;
	}
}
普通類型去接,結果爲:
	構造函數!
	拷貝構造!
	異常捕獲!
	析構函數!
	析構函數!
*/

/*
void test01();{
	try {
		func();
	}
	catch (MyException& e) {
		cout << "異常捕獲!" << endl;
	}
}
引用去接,結果爲:
	構造函數!
	異常捕獲!
	析構函數!
*/
/*
void test01();{
	try {
		func();
	}
	catch (MyException* e) {
		cout << "異常捕獲!" << endl;
		detele e;
	}
}
指針去接,結果爲:
	構造函數!
	異常捕獲!
	析構函數!
*/
相關文章
相關標籤/搜索