王老师 C++ 异常处理

原创 2006年06月17日 19:16:00

异常:程序执行期间,可检测到的不正常情况。

例如:0作除数;数组下标越界;打开不存在的文件;远程机器连接超时;malloc失败等等。

程序的两种状态:

正常状态和异常状态,发生不正常情况后,进入异常状态,从当前函数开始,按调用链的相反次序,查找处理该异

常的程序片断。

1.throw 表达式

语义:用表达式的值生成一个对象(异常对象),程序进入异常状态。

Terminate函数,终止程序的执行。

2.try-catch语句

try{

    包含可能抛出异常的语句;

}catch(类型名 [形参名]){

}catch(类型名 [形参名]){

}

例子程序:

#include <iostream>
#include <math.h>

using namespace std;

double sqrt_delta(double d){
 if(d < 0)
  throw 1;
 return sqrt(d);
}

double delta(double a, double b, double c){
 double d = b * b - 4 * a * c;
 return sqrt_delta(d);
}

void main()
{
 double a, b, c;
 cout << "please input a, b, c" << endl;
 cin >> a >> b >> c;

 while(true){
  try{
   double d = delta(a, b, c);
   cout << "x1: " << (d - b) / (2 * a);
   cout << endl;
   cout << "x2: " << -(b + d) / (2 * a);
   cout << endl;
   break;
  }catch(int){
   cout << "delta < 0, please reenter a, b, c.";
   cin >> a >> b >> c;
  }
 }
}

3.重新抛出异常

语法: throw;

语义:重新抛出原有的异常对象。如果在throw后面有表达式,则抛出新的异常对象。

例子程序:

#include <iostream>
using namespace std;

void fun(int x){
 try{
  if(x == 1)
   throw 1;
  if(x == 2)
   throw 1.0;
  if(x == 3)
   throw '1';
 }catch(int){
  cout << "catch an int in fun()" << endl;
 }catch(double){
  cout << "catch an double in fun()" << endl;
 }
 cout << "testing exception in fun()..."<< endl;
}

void gun()
{
 try{
  //fun(1);
  //fun(2);
  //fun(3);
  fun(4);
 }catch(char){
  cout << "catch a char in gun()" << endl;
 }
 cout << "testing exception in gun()..."<< endl;
}

int main()
{
 gun();
}

4.扑获所有异常

catch(...){

}

下面的程序是不对的:

error C2311: 'int' : is caught by '...' on line 7

#include <iostream>
using namespace std;

void fun()
{
 try{
 }catch(...){
  cout << "catch all exception ..." << endl;
 }catch(int){
  cout << "catch int exception ..." << endl;
 }
}

5.异常规范

指出函数可以抛出的所有异常类型名。

语法:值类型 函数名(形参表) throw(类型名表) 函数体

空异常规范表示不抛出异常;

例如:

warning C4297: 'function' : function assumed not to throw an exception but does
        __declspec(nothrow) or throw() was specified on the function

#include <iostream>
using namespace std;

void function(int x) throw()
{
 if(x == 1)
  throw 1;
}

无异常规范表示可抛出任何异常。

异常规范违例,在函数的声明中并没有声明抛出该类异常,但在程序中却抛出了该类的异常?例如:

warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)

void function(int x) throw (int)
{
 if(x == 1)
  throw 1.5;
}

注:在g++中并未警告。

对于函数指针,例如:

#include <iostream>
using namespace std;

void function(int x)throw(int)
{
        if(x == 1)
                throw 1;
}

int main()
{
        void (*fp)(int)throw(char);
        fp = function;
        fp(1);
}

同样的,在g++中没有警告,但在vc8中提出警告:

warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)

<补充>
异常规范违例,例子程序如下:
#include <iostream>
using namespace std;
class A
{
};

void function(int x)throw(int)
//void function(int x)throw(A*)
{
if(x == 1)
throw new A;
}

void test() throw (A* )
{
//void (*fp)(int)throw(A);
void (*fp)(int)throw(int);
fp = function;
try{
fp(1);
}catch(int)
{
cout << "test" << endl;
throw;
}
}

int main()
{
try{
test();
}catch(A*){
cout << "test in main" <<endl;
}
return 0;
}
这个代码在vc8和g++环境中的运行结果不同? 

<补充>
1.异常处理仅仅通过类型而不是通过值来匹配的,否则又回到了传统的错误处理技术上去了,所以catch块的参数可以没有参数名称,只需要参数类型,除非要使用那个参数。
2.虽然异常对象看上去像局部对象,但并非创建在函数栈上,而是创建在专用的异常栈上,因此它才可以跨接多个函数而传递到上层,否则在栈清空的过程中就会被销毁。
3.函数原型中的异常说明要与实现中的异常说明一致,否则容易引起异常冲突。由于异常处理机制是在运行时有异常时才发挥作用的,因此如果函数的实现中抛出了没有在其异常说明列表中列出的异常,则编译器并不能检查出来。但是当运行时如果真的抛出了这样的异常,就会导致异常冲突。因为你没有提示函数的调用者:该函数会抛出一种没有被说明的即不期望的异常,于是异常处理机制就会检测到这个冲突并调用标准库函数unexcepted(),unexcepted()的默认行为就是调用terminate()来结束程序。
实际工作中使用set_unexcepter()来预设一个回调函数。
4.当异常抛出时局部对象如何释放?
Bjarne Stroustrup引入了“resource acquistion is initialization”思想,异常处理机制保证:所有从try到throw语句之间构造起来的局部对象的析构函数将被自动调用,然后清退堆栈(就像函数正常退出一样)。如果一直上溯到main函数后还没有找到匹配的catch块,那么系统调用terminate()终止整个程序,这种情况下不能保证所有局部对象会被正确地销毁。
5.catch块的参数应采用引用传递而不是值传递,不仅可以提高效率,还可以利用对象的多态性。另外,派生类的异常扑获要放到父类异常扑获的前面,否则,派生类的异常无法被扑获。catch(void *)要放到catch(...)前面。
6.编写异常说明时,要确保派生类成员函数的异常说明和基类成员函数的异常说明一致,即派生类改写的虚函数的异常说明至少要和对应的基类虚函数的异常说明相同,甚至更加严格,更特殊。

C++异常处理机制总结

参考文档:《C++编程思想》《C++Primer》《More effective C++》 一、             传统的错误处理机制: 1.         返回值或全局错误状态标志。缺点:需...
  • MulinB
  • MulinB
  • 2007年08月29日 10:07
  • 2268

C++异常处理的理解

1.异常的基本概念和选择 异常处理try语句会导致比较大的开销,异常规范也会导致比较多的开销(每个都比自己原来大概增大5%-10%左右,速度也减慢原来同等的比例,原因是需要额外的内存和计算来详细记录...
  • Blues1021
  • Blues1021
  • 2015年04月18日 08:15
  • 754

深入理解C++中的异常处理机制

深入理解C++中的异常处理机制异常处理增强错误恢复能力是提高代码健壮性的最有力的途径之一,C语言中采用的错误处理方法被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编写错误处理代码,这样会使...
  • zhangyifei216
  • zhangyifei216
  • 2015年12月26日 21:29
  • 3066

JAVA异常处理 与C++的不同

*Java异常处理模型   对于一个非常熟悉 C++ 异常处理模型的程序员来说,它几乎可以不经任何其它培训和学习,就可以完全接受和能够轻松地使用 Java 语言中的异常处理编程方法。这是因为 Java...
  • ljlove2008
  • ljlove2008
  • 2008年10月14日 23:32
  • 2472

C++异常处理实例

/************************************************************************************************ *...
  • JarvisChu
  • JarvisChu
  • 2011年07月22日 22:41
  • 4027

对使用 C++ 异常处理应具有怎样的态度?

http://www.zhihu.com/question/22889420 来自知乎 陈硕,Linux C++程序员,muduo 网络库作者 王召京...
  • wangyin159
  • wangyin159
  • 2015年06月28日 08:21
  • 565

C++ 异常处理例子

#include #include #include using namespace std; #ifdef _WIN32 //#include #include #end...
  • earbao
  • earbao
  • 2016年11月25日 11:59
  • 252

C/C++异常处理的对比

本文主要介绍C异常处理与C++异常处理的区别。 包括errno、signal、nonlocal goto、异常的捕获、异常规格说明(exception specification)、标准异常对象等。...
  • yeming81
  • yeming81
  • 2010年06月16日 00:19
  • 4699

Unix/Linux C++应用开发-异常以及错误处理

计算机应用程序中离不开错误处理,尤其是生产型大型软件系统。应用软件系统运行属于循环处理事务,出错后需要保证不能让软件程序直接退出。这就需要使用一定的程序容错处理来应对。一般情况下,大型软件开发中的软件...
  • wangfengwf
  • wangfengwf
  • 2013年09月11日 21:15
  • 30142

C++技术点积累(6)——异常处理、输入和输出流

C++技术点积累: 1、异常处理机制: 2、输入和输出流:
  • songshiMVP1
  • songshiMVP1
  • 2015年09月20日 15:51
  • 714
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:王老师 C++ 异常处理
举报原因:
原因补充:

(最多只允许输入30个字)