-------------------------------------资源来源于网络,仅供自学使用,如有侵权,联系我必删.
第一:
深入异常处理
问题
有时在工程中只关心是否产生了异常 , 而不关心具体的异常类型 , C++ 语言可以做到吗 ?
C++ 中的 catch 语句可以使用 … 捕获所有的异常
#include <cstdlib>
#include <iostream>
using namespace std;
int test(int i)
{
if( i == 1 )
{
throw "p";
}
if( i == 2 )
{
throw 0.5;
}
if( i == 3 )
{
throw 3;
}
if( i == 4 )
{
throw 'c';
}
return i;
}
int main(int argc, char *argv[])
{
for(int i=0; i<10; i++)
{
try
{
cout<<test(i)<<endl;
}
catch(char e)//字符信息
{
cout<<"Exception: "<<e<<endl;
}
//一般作为最后一个异常处理块出现
catch(...)//使用 … 捕获所有的异常
{
cout<<"Exception Occur"<<endl;
}
}
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
? catch( …) 可以捕获所有异常但却无法得到异常信息
? catch( …)一般作为最后一个异常处理块出现
看见代码中的 catch 就要意识到这里在处理异常情况 , 而异常是在对应的 try 中产生的
第二:
在 catch 语句块中仍然可以抛出异常
#include <cstdlib>
#include <iostream>
using namespace std;
int test(int i)
{
if( (6 <= i) && (i <= 9) )
{
throw i;//抛出异常
}
return i;
}
int main(int argc, char *argv[])
{
try //2
{
for(int i=0; i<10; i++)
{
try
{
cout<<test(i)<<endl;
}
catch(int e)
{
cout<<"Exception: "<<e<<endl;
//跑出的异常由外层try捕获 --> catch(int e) 捕获
throw e;//1
}
}
}
catch(int e)//3
{
cout<<"Catch: "<<e<<endl;
}
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
第三:
在 catch( …) 语句块中 , 可以通过不带参数的 throw 语句抛出捕获的异常
#include <cstdlib>
#include <iostream>
using namespace std;
int test(int i)
{
if( (6 <= i) && (i <= 9) )
{
throw i;
}
return i;
}
int main(int argc, char *argv[])
{
try
{
for(int i=0; i<10; i++)
{
try
{
cout<<test(i)<<endl;
}
catch(...)
{
cout<<"Exception Occur"<<endl;
throw;//没有参数的throw
}
}
}
catch(int e)
{
cout<<"Catch: "<<e<<endl;
}
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
第四:
异常与对象
? 不要在构造函数中抛出异常
? 在构造函数可能申请系统资源 , 而在构造函数中抛出异常会导致对象构造不完全
? 不完全对象的析构函数是不会被调用的 , 因此可能造成资源泄漏
构造函数中的异常示例
#include <cstdlib>
#include <iostream>
using namespace std;
class Test
{
int* p;
public:
Test()
{
cout<<"Test()"<<endl;
p = new int[5];//申请5个整型数
throw 10;
}
~Test()//不会调用析构函数,20个字节资源泄漏
{
cout<<"~Test()"<<endl;
delete[] p;
}
};
int main(int argc, char *argv[])
{
try
{
Test t;
}
catch(int e)
{
cout<<"Catch: "<<e<<endl;
}
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
第五:
工程中的异常应用
? 在工程中会定义一系列的异常类
? 通过继承 , 可以得到一个异常类族
? 每个类代表工程中可能出现的一种异常类型
? 由于对象构造与拷贝的开销 , 在定义 catch 语句块时使用引用作为参数
? 在工程中可以使用标准库中的异常类
? 可将标准库中的异常类作为基类派生新的异常类
? 标准库中的异常都是从 exception 类派生的
? exception 类有两个主要的分支
? logic_error 用于描述程序中出现的逻辑错误
? 如 : 传递无效参数
? runtime_error 用于描述无法预料的事件所造成的错误
? 如 : 内存耗尽 , 硬件错误
标准库中的异常
? logic_error 和 runtime_error 都提供了一个参数为字符串的构造函数 , 这样就可以保持错误信息
? 通过 what() 成员函数就可以得到错误的信息
异常的工程应用初探
#include <cstdlib>
#include <iostream>
#include <stdexcept>//标准库异常
using namespace std;
class divide_by_zero : public logic_error//继承定义新的异常类
{
public:
divide_by_zero(const char* s) : logic_error(s)
{
}
};
double Div(double a, double b)
{
if( (-0.00000001 < b) && ( b < 0.00000001) )
{
throw divide_by_zero("Divide by zero...");//抛出异常
}
return a / b;
}
int main(int argc, char *argv[])
{
try
{
cout<<Div(1, 0)<<endl;
}
catch(exception& e)//根信息exception 作为异常类捕获,可以捕获所有异常,异常信息
{
cout<<e.what()<<endl;//得到错误的信息
}
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
第六:
函数级try 语法
可以将函数体作为一个完整的 try 语句块
#include <cstdlib>
#include <iostream>
#include <stdexcept>
using namespace std;
int func1(int i)
{
try
{
if( i > 0 )
{
return i;
}
else
{
throw "error";
}
}
catch(...)
{
return -1;
}
}
int func2(int i) try
{
if( i > 0 )
{
return i;
}
else
{
throw "error";
}
}
catch(...)
{
return -1;
}
int main(int argc, char *argv[])
{
for(int i=0; i<5; i++)
{
cout<<func2(i)<<endl;
}
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
函数级 try 语法可以更好将正常逻辑代码与异常处理代码分开 , 提高代码的可读性与维护性
小结:
? catch( …) 可以捕获所有异常
? catch( …) 经常作为最后一个 catch 语句出现
? 不要在构造函数中抛出异常 , 这样可能造成资源泄露
? 工程中经常以标准库中的异常类作为项目异常的基础
? 函数级 try语句块能够更好的提高代码的维护性