c++中trycatch的⽤法⼩结
在c++中,可以直接抛出异常之后⾃⼰进⾏捕捉处理,如:(这样就可以在任何⾃⼰得到不想要的结果的时候进⾏中断,⽐如在进⾏数据库事务操作的时候,如果某⼀个语句返回SQL_ERROR则直接抛出异常,在catch块中进⾏事务回滚(回滚怎么理解?))。
#include <iostream>
#include <exception>
using namespace std;
int main () {
try
{
throw 1;
throw "error";
}
catch(char *str)
{
cout << str << endl;
}
catch(int i)
{
cout << i << endl;
}
}
也可以⾃⼰定义异常类来进⾏处理:
#include <iostream>
#include <exception>
using namespace std;
//可以⾃⼰定义Exception
class myexception: public exception
{
virtual const char* what() const throw()
{
return "My exception happened";
}
}myex;
int main () {
try
{
if(true) //如果,则抛出异常;
宗亲联谊会发言稿
throw myex;
}
catch (exception& e)
{
cout << e.what() << endl;
}
return 0;
}
同时也可以使⽤标准异常类进⾏处理:
#include <iostream>
#include <exception>
using namespace std;
int main () {
try
{
int* myarray= new int[100000];
}
catch (exception& e)
{
cout << "Standard exception: " << e.what() << endl;
}
return 0;
60岁}
⼀、简单的例⼦
⾸先通过⼀个简单的例⼦来熟悉C++ 的 try/catch/throw(可根据单步调试来熟悉,try catch throw部分是如何运⾏的):
#include <stdlib.h>
#include "iostream"
using namespace std;
double fuc(double x, double y) //定义函数
{
if(y==0)
{
throw y; //除数为0,抛出异常
}
return x/y; //否则返回两个数的商
}
int _tmain(int argc, _TCHAR* argv[])
{
double res;
try //定义异常
{
res=fuc(2,3);
cout<<"The result of x/y is : "<<res<<endl;
res=fuc(4,0); //出现异常
}
catch(double) //捕获并处理异常
{
cerr<<"error of dividing zero.\n";
exit(1); //异常退出程序
}
return 0;
}
catch 的数据类型需要与throw出来的数据类型相匹配的。
⼆、catch(...)的作⽤
catch(…)能够捕获多种数据类型的异常对象,所以它提供给程序员⼀种对异常对象更好的控制⼿段,使开发的软件系统有很好的可靠性。因此⼀个⽐较有经验的程序员通常会这样组织编写它的代码模块,如下:
void Func()
{
try
{
// 这⾥的程序代码完成真正复杂的计算⼯作,这些代码在执⾏过程中
// 有可能抛出DataType1、DataType2和DataType3类型的异常对象。
}
catch(DataType1& d1)
{
}
catch(DataType2& d2)
{
}
catch(DataType3& d3)
{
}
/********************************************************* 注意上⾯try block中可能抛出的DataType1、DataType2和DataType3三
种类型的异常对象在前⾯都已经有对应的catch block来处理。但为什么
还要在最后再定义⼀个catch(…) block呢?这就是为了有更好的安全性和
可靠性,避免上⾯的try block抛出了其它未考虑到的异常对象时导致的程
序出现意外崩溃的严重后果,⽽且这在⽤VC开发的系统上更特别有效,因
为catch(…)能捕获系统出现的异常,⽽系统异常往往令程序员头痛了,现
在系统⼀般都⽐较复杂,⽽且由很多⼈共同开发,⼀不⼩⼼就会导致⼀个
指针变量指向了其它⾮法区域,结果意外灾难不幸发⽣了。catch(…)为这种
潜在的隐患提供了⼀种有效的补救措施。 *********************************************************/
catch(…)
{
}
}
三、异常中采⽤⾯向对象的处理
⾸先看下⾯的例⼦:
void OpenFile(string f)
{
胖小猪try
{
// 打开⽂件的操作,可能抛出FileOpenException
}
catch(FileOpenException& fe)
{
// 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数
// 正常返回;否则必须重新抛出这个异常,以供上层的调⽤函数来能再次处
// 理这个异常对象
int result = ReOpenFile(f);
if (result == fal) throw;
}
}
void ReadFile(File f)
{
try
{
// 从⽂件中读数据,可能抛出FileReadException
}
catch(FileReadException& fe)
{
// 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数
// 正常返回;否则必须重新抛出这个异常,以供上层的调⽤函数来能再次处
// 理这个异常对象
int result = ReReadFile(f);
if (result == fal) throw;
}
}
void WriteFile(File f)
{
try
{
// 往⽂件中写数据,可能抛出FileWriteException
}
catch(FileWriteException& fe)
{
// 处理这个异常,如果这个异常可以很好的得以恢复,那么处理完毕后函数
// 正常返回;否则必须重新抛出这个异常,以供上层的调⽤函数来能再次处理这个异常对象 int result = ReWriteFile(f);
if (result == fal) throw;
}
}
void Func()
{
try
{
// 对⽂件进⾏操作,可能出现FileWriteException、FileWriteException
// 和FileWriteException异常
OpenFile(…);
ReadFile(…);
WriteFile(…);
}
// 注意:FileException是FileOpenException、FileReadException和FileWriteException
// 的基类,因此这⾥定义的catch(FileException& fe)能捕获所有与⽂件操作失败的异
// 常。
catch(FileException& fe)
{
ExceptionInfo* ef = fe.GetExceptionInfo();
cout << “操作⽂件时出现了不可恢复的错误,原因是:”<< fe << endl;傣族服饰特点
}
}
下⾯是更多⾯向对象和异常处理结合的例⼦:
#include <iostream.h>
class ExceptionClass
{
char* name;
public:
ExceptionClass(const char* name="default name")
{
cout<<"Construct "<<name<<endl;
this->name=name;
}
~ExceptionClass()
cout<<"Destruct "<<name<<endl;
}
void mythrow()
{
throw ExceptionClass("my throw");
}
}
void main()
{
ExceptionClass e("Test");
try
{
}
catch(...)
{
cout<<”*********”<<endl;
}
}
这是输出信息:
Construct Test
Construct my throw
Destruct my throw
****************
Destruct my throw (这⾥是异常处理空间中对异常类的拷贝的析构)
借记卡年费
Destruct Test
======================================
不过⼀般来说我们可能更习惯于把会产⽣异常的语句和要throw的异常类分成不同的类来写,下⾯的代码可以是我们更愿意书写的:
class ExceptionClass
{
public:
ExceptionClass(const char* name="Exception Default Class")低通滤波器原理
{
八珍粉配方cout<<"Exception Class Construct String"<<endl;
}
~ExceptionClass()
{
cout<<"Exception Class Destruct String"<<endl;
}
void ReportError()
{
cout<<"Exception Class:: This is Report Error Message"<<endl;
}
};
class ArguClass
{
char* name;
public:
ArguClass(char* name="default name")
{
cout<<"Construct String::"<<name<<endl;
this->name=name;
}
~ArguClass()
{
cout<<"Destruct String::"<<name<<endl;
}
void mythrow()
{
throw ExceptionClass("my throw");
}
};
_tmain()
{
ArguClass e("haha");
try
}
catch(int)
{
cout<<"If This is Message display screen, This is a Error!!"<<endl; //这⾏不会执⾏
}
catch(ExceptionClass pTest)
{
pTest.ReportError();
}
catch(...)
{
cout<<"***************"<<endl;
}
}
输出Message:
Construct String::haha
Exception Class Construct String
Exception Class Destruct String
Exception Class:: This is Report Error Message
Exception Class Destruct String
Destruct String::haha
四、构造和析构中的异常抛出
先看个程序,假如我在构造函数的地⽅抛出异常,这个类的析构会被调⽤吗?可如果不调⽤,那类⾥的东西岂不是不能被释放了?
#include <iostream.h>
#include <stdlib.h>
class ExceptionClass1
{
char* s;
public:
ExceptionClass1()
{
cout<<"ExceptionClass1()"<<endl;
s=new char[4];
cout<<"throw a exception"<<endl;
throw 18;
}
~ExceptionClass1()
{
cout<<"~ExceptionClass1()"<<endl;
delete[] s;
}
};
void main()
{
try
{
ExceptionClass1 e;
}
catch(...)
{}
}
结果为:
ExceptionClass1()
throw a exception
在这两句输出之间,我们已经给S分配了内存,但内存没有被释放(因为它是在析构函数中释放的)。应该说这符合实际现象,因为对象没有完整构造。
为了避免这种情况,我想你也许会说:应避免对象通过本⾝的构造函数涉及到异常抛出。即:既不在构造函数中出现异常抛出,也不应在构造函数调⽤的⼀切东西中出现异常抛出。
但是在C++中可以在构造函数中抛出异常,经典的解决⽅案是使⽤STL的标准类auto_ptr。