文档章节

C++异常---总结和相关示例代码展示

西昆仑
 西昆仑
发布于 2012/01/08 22:02
字数 1628
阅读 414
收藏 1

异常基本概念

异常即程序在运行期间产生的非预期性错误,如内存配额不足、文件不存在、网络不可用、SQL语句非法等。

异常分为可恢复性异常不可恢复性异常

异常是否可恢复,不同的应用场景将有不同的理解。例如,对于内存配合不足,在短暂的峰涌情况下内存能够快速恢复则属于可恢复性异常,因为一但被释放和回收,程序将回到常态;若内存长时间得不到释放,则属于不可恢复性异常,此时应当终止程序的运行。

异常又可分为已知异常和未知异常。已知异常是指程序编写者事先考虑到的异常,对异常有清晰的定义和处理逻辑,并在程序中进行捕捉;未知异常是指程序编写者事先未察觉到的异常,可以理解为程序bug。

异常捕获是一把双刃剑,对异常进行显示捕获,尤其对于bug型的未知异常,需要找出产生异常的原因和代码进行修复,即需要考虑异常的分析定位机制。因此,对于未知异常或者无法处理的异常,不应当使用catch(…)笼统的进行捕获,当不需要关心异常或者无法处理异常的时候,就应该避免捕获异常或者将未处理的异常再次抛出,以便交由bugreport统一对未处理异常进行捕获、分析。

函数的异常声明

在函数的声明后面使用throw关键字可对函数的异常产生进行限制。

不允许函数抛出任何异常

void f() throw(); 表示f函数不允许抛出任何异常;以VS2005编译器为例,若在f函数中抛出异常,编译时会有如下提示:

warning C4297: 'f' : function assumed not to throw an exception but does

1>        __declspec(nothrow) or throw() was specified on the function

但异常还是能正常抛出和被捕获。

 

允许函数抛出任意异常

void f() throw(…);表示允许f函数抛出任意异常。

允许函数抛出指定类型的异常

void f() throw(MyException1,MyException2);表示允许函数f抛出MyException1和MyException2两种类型的异常。以vs2005为例,在f中抛出其他类型的异常,编译未见提示,且异常能正常抛出和被捕获。

异常的抛出

使用关键字throw抛出异常,有如下两种语法。

throw express;抛出express所代表的表达式的异常,异常类型为表达式的值的类型,异常的值为表达式的值。例如,

try{

   throw 10;
}catch(int e){

   //progress....
}

throw;将异常继续“向上传递”。例如,

try{

     throw 10;
}catch(int e){

         throw...
}

异常类型

任何类型都可以作为异常类型,包括基本数据类型,如int、double、char等;还包括类类型,如std:string;还包括自定义异常类型,即从std::exception派生的子类。

异常对象的传递

自定义的异常类:CCustomException

#pragma once

#include <string>
using namespace std;


class CCustomException : public std::exception
{
		public:
			CCustomException(void);
			CCustomException(const char*);
			~CCustomException(void);
		

			std::string getMsg();
			void setMsg(std::string msg);
			virtual const char* what() const;
		private:
			std::string m_msg;
};

#include "StdAfx.h"
#include "CustomException.h"

CCustomException::CCustomException(void)
{
}

CCustomException::~CCustomException(void)
{
}

CCustomException::CCustomException(const char* msg)
{
		m_msg = msg;
}

std::string CCustomException::getMsg()
{
		return m_msg;
}

void CCustomException::setMsg(std::string msg)
{
		m_msg = msg;
}

const char* CCustomException::what() const
{
	 return m_msg.c_str();
}

main函数如下:

// ExceptionExample.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "CustomException.h"
#include <iostream>

void exceptionTest1()  throw(CCustomException)
{
		throw CCustomException("this is CCustomException Test1!");
		return;
}

void exceptionTest2()  throw(CCustomException*)
{
	throw new CCustomException("this is CCustomException Test2!");
	return;
}

void exceptionTest3()  throw(CCustomException&)
{
	throw(CCustomException("this is CCustomException Test3!"));
	return;
}

void Test1()
{
	try
	{
		exceptionTest1();
	}
	catch (std::exception e)
	{
		cout<<e.what()<<endl;
	}
}

void Test2()
{
	try
	{
		exceptionTest2();
	}
	catch (std::exception *e)
	{
		cout<<e->what()<<endl;
		delete e;
	}
}

void Test3()
{
	try
	{
		exceptionTest3();
	}
	catch (std::exception  &e)
	{
		cout<<e.what()<<endl;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
		Test1();
		Test2();
		Test3();
	
		getchar();
		return 0;
}

输出结果如下:

异常对象的传递和函数参数的传递一样,有值传递、指针传递和引用传递3种传递方式。

值传递会产生临时对象拷贝,且不支持多态。,虽然CCustomException是std::exception的子类,但是仍然不能调用CCustomException的what函数,输出了Unknown Message。

指针传递

指针传递可以实现多态,但会将临时对象的地址作为指针传出去,出现悬挂指针错误。如果在堆上分配内存空间,又不知道何时恰当的删除对象,二来代码可读性、可维护性遭到破坏,违反了内存空间从哪里申请得到就在哪里释放的内存分配释放原则。

值引用传递既能避免临时对象的拷贝,又能支持多态,且没有对象释放问题。推荐采用值引用的方式传递异常对象。输出结果为:This is CCustomException Test3.

catch的匹配规则

异常匹配采用自底向上的匹配顺序进行匹配,即先在异常产生的函数中进行匹配,若该造成该异常的代码没有被try…catch…捕获或者catch类型不匹配,则向上传递直到匹配到第一条catch结束匹配,或则未发现任何匹配的catch则产生未处理异常交由运行时环境处理。

对于基本数据类型的异常,采用严格类型匹配机制,不支持类型转换

对于自定义类型,基类类型能够匹配子类异常对象,子类类型不能匹配基本异常对象。

C++提供了强大的异常处理机制将异常产生和异常处理的代码分离,即将程序的正常业务逻辑和错误处理逻辑进行分离,并在不改变函数原型的情况下,实现异常对象的“向上”传递。

C++的异常处理机制有3部分组成:try(检查),throw(抛出),catch(捕获)。把需要检查的语句放在try模块中,检查语句发生错误,throw抛出异常,发出错误信息,由catch来捕获异常信息,并加以处理。一般throw抛出的异常要和catch所捕获的异常类型所匹配。异常处理的一般格式为:

try
  {
    被检查语句
    throw 异常
  }
  catch(异常类型1)
  {
    进行异常处理的语句1
  }
  catch(异常类型2)
  {
    进行异常处理的语句2
  }


本文转载自:http://blog.csdn.net/m_star_jy_sy/article/details/7175683

西昆仑

西昆仑

粉丝 137
博文 141
码字总数 102735
作品 0
南京
高级程序员
私信 提问
FFLIB之FFLUA——C++嵌入Lua&扩展Lua利器

摘要: 在使用C++做服务器开发中,经常会使用到脚本技术,Lua是最优秀的嵌入式脚本之一。Lua的轻量、小巧、概念之简单,都使他变得越来越受欢迎。本人也使用过python做嵌入式脚本,二者各有特...

知然
2013/01/27
0
0
Android NDK C++开发注意事项总结

相信Android开发者都喜欢用C++编写一些高效的应用,有关Android NDK的C++开发相关知识总结如下: 从Android NDK r5开始支持了STL Port,在这个版本开始就可以使用部分STL库的功能了,比如说v...

阿酷
2011/10/21
1K
0
在MFC程序中使用AnyCAD三维控件

AnyCAD三维控件有.Net版本和C++两个版本,使用C++要比C#稍微繁杂一点。SDK中提供了针对MFC的文档视图的封装,只需改一下几个基类即可。 准备 VS2010 下载C++版本的AnyCAD图形控件:http://pa...

AnyCAD三维控件
2015/05/06
891
0
Android NDK C++开发注意事项总结

相信Android开发者都喜欢用C++编写一些高效的应用,有关Android NDK的C++开发相关知识总结如下: 1. 从Android NDK r5开始支持了STL Port,在这个版本开始就可以使用部分STL库的功能了,比如说...

android技术开发
2013/08/29
2.7K
2
c语言基础学习11_项目实战:IDE(集成开发环境)

============================================================================= ============================================================================= 涉及到的知识点有: 一......

黑泽明军
2018/01/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

当阿里云工程师回到了家乡......

根据真实故事改编 略有浮夸 但重要的是 9月25日13:30-16:30 云栖大会「5G边缘计算专场」 一定要来哦 !!! 本文作者:樰篱 原文链接 本文为云栖社区原创内容,未经允许不得转载。...

Mr_zebra
25分钟前
5
0
文件操作工具类 FileUtils常用方法

文件操作工具类(FileUtils) 使用该工具类的前提是项目里导入commons-io 包 import org.apache.commons.io.FileUtils; List<String> lines=new ArrayList<String>(); lines.add("欢迎访问:......

AndLong
32分钟前
5
0
maven-shade-plugin

最近,用规则引擎(drools)的封装了一个jar包,给别人使用。用的是maven-assembly-plugin打的包,可以把多个jar包里的class 给打成一个jar,感觉还是满好用的,但是打包成功后,发现报空指针错...

internetafei
36分钟前
5
0
Cassandra repair 工具使用

前言 Cassandra是一款去中心化的分布式数据库。一份数据会分布在多个对等的节点上,即有多个副本。我们需要定期的对多个副本检查,看是否有不一致的情况。比如因为磁盘损坏,可能会导致副本丢...

阿里云官方博客
39分钟前
5
0
element-vue使用富文本编辑器【前端】

一、前言 1.富文本编辑器选择的为vue-quill-editor 官方地址:https://quilljs.com/docs/quickstart/ 2.安装 cnpm install vue-quill-editor cnpm install quill 3.在对应的页面引入,在com...

一代码农码一代
45分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部