C++ 异常机制(上)
一、概念
异常:存在于运行时的反常行为,这些行为超过了函数的正常的功能范围。
异常处理:处理程序中的错误,异常处理机制为程序中异常检测和异常处理这两部分的协作提供支持。
在C++中,异常处理包括:
- throw表达式,表示遇到了无法处理的问题
- try语句块,处理异常;以关键字try开始,一个或多个catch结束
- 一套异常类,用于在throw表达式和相关的catch子句之间传递异常的信息。
二、异常的好处
- 整性返回值没有语义信息,而异常包含语义信息,有时从类名便可看出。
- 异常作为一个类,有自己的成员,可以传递足够的信息。
- 函数的返回值可以忽略,异常不可以忽略,可以使程序更加健壮。
三、基本语法
#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();
}
四、栈解旋
异常被抛出后,从进入try块起,到异常被抛前,这期间在栈上构造的所有对象,都会被自动析构,析构的顺序与构造的顺序相反,这一过程即为栈解旋。
构造函数没有返回类型,无法通过返回值来报告运行状态,所以通过异常机制来解决构造函数的出错问题。
#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;
}
/*
结果:
    对象构建!
	对象构建!
	对象析构!
	对象析构!
	异常捕获!
*/
五、异常接口声明
- 为了加强程序的可读性,可以在函数声明中列出可能抛出的所有异常类型,例如:
 void func() throw (A, B, C , D); //这个函数func()能够且只能抛出类型A B C D及其子类型的异常。
- 如果在函数声明中没有包含异常接口声明,则次函数可以抛掷任何类型的异常,例如:
 void func();
- 一个不抛掷任何类型异常的函数可以声明为:
 void func() throw();
- 如果一个函数抛出了它的异常接口声明所不允许抛出的异常,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;
}
//结果: 未知类型异常!
六、异常对象的内存模型
throw的异常是有类型的,可以是数字、字符串、类对象,catch需严格匹配异常类型。
#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* 异常捕获!
我刚写异常!
*/
七、异常对象的生命周期
- catch里可以用普通类型元素,引用,指针去接
- 普通元素去接,异常对象catch处理完之后就析构
- 引用的话,不用调用拷贝构造,异常对象catch处理完之后就析构
- 指针接,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;
	}
}
指针去接,结果为:
	构造函数!
	异常捕获!
	析构函数!
*/
C++ 异常机制(上)的更多相关文章
- Atitit 异常机制与异常处理的原理与概论
		Atitit 异常机制与异常处理的原理与概论 1. 异常vs 返回码1 1.1. 返回码模式的处理 (瀑布if 跳到失败1 1.2. 终止模式 vs 恢复模式(asp2 1.3. 异常机制的设计原理 ... 
- C++ 异常机制分析
		C++异常机制概述 异常处理是C++的一项语言机制,用于在程序中处理异常事件.异常事件在C++中表示为异常对象.异常事件发生时,程序使用throw关键字抛出异常表达式,抛出点称为异常出现点,由操作系统 ... 
- 【转载】C++异常机制的学习
		参考了这篇文章:http://blog.chinaunix.net/uid-24517549-id-4079174.html 关于线程 进程和线程的概念相信各位看官早已耳熟能详.在这里,我只想带大家回 ... 
- Java异常机制
		Java异常分类 异常表明程序运行发生了意外,导致正常流程发生错误,例如数学上的除0,打开一个文件但此文件实际不存在,用户输入非法的参数等.在C语言中我们处理这类事件一般是将其与代码正常的流程放在一起 ... 
- 黑马程序员——【Java基础】——面向对象(二)异常机制、包(Package)
		---------- android培训.java培训.期待与您交流! ---------- 一.异常机制 (一)异常概述 1.异常:就是程序在运行时出现不正常情况. 2.异常类:程序在运行时,出现的 ... 
- C 几种异常机制简单讲述
		引言 这是关于C中如何使用异常机制的讨论.顺带讲一讲C中魔法函数的setjmp内部机制.通过它实现高级的异常try...catch. 允许我先扯一段面试题. 对于计算机面试题. 算法题等.觉得还是有意 ... 
- C++异常机制知识点
		在这里总结一下,C++中的异常机制,以及如何使用异常的知识点 C++中处理异常的过程是这样的:在执行程序发生异常,可以不在本函数中处理,而是抛出一个错误信息,把它传递给上一级的函数来解决,上一级解决 ... 
- [转载]C++异常机制的实现方式和开销分析
		原文章网址:http://baiy.cn/doc/cpp/inside_exception.htm C++异常机制的实现方式和开销分析 白杨 http://baiy.cn 在我几年前开始写<C+ ... 
- C++异常机制的实现方式和开销分析
		C++异常机制的实现方式和开销分析 白杨 http://baiy.cn http://baiy.cn/doc/cpp/inside_exception.htm 在我几年前开始写<C++编码规范与 ... 
随机推荐
- day108:MoFang:首页检测用户是否登录&在项目中使用MongoDB&用户页面更新用户信息&交易密码界面实现
			目录 1.首页页面也要检测用户是否登录 2.在flask中使用MongoDB 3.用户页面更新用户信息 4.交易密码界面/密码修改界面/昵称修改界面初始化 5.交易密码实现 1.首页页面也要检测用户是 ... 
- STL——容器(deque)deque 的删除 clear() erase()
			deque.clear(); //移除容器的所有数据 1 #include <iostream> 2 #include <deque> 3 4 using namespace ... 
- Linux(CentOS7)安装Nginx(附简单配置)
			1. 安装make yum -y install gcc automake autoconf libtool make 2. 安装gcc yum -y install gcc gcc-c++ 3. 安 ... 
- 浅谈JAVA代码优化
			JAVA代码的优化分为两个方面: 一.减小代码的体积.二.提高代码的执行效率. ============================================================ ... 
- 记MSSQL和MYSQL
			简单的说就是mssql是asp和asp.net是黄金搭档mysql是PHP是黄金搭档他们相互结合比较好用,速度也比较快!!!MSSQL就是SQLSERVER,MS是微软的缩写MYSQL是一套免费的数据 ... 
- Mysql技术内幕之InnoDB锁探究
			自7月份换工作以来,期间一直在学习MySQL的相关知识,听了一些视频课,但是一直好奇那些讲师的知识是从哪里学习的.于是想着从书籍中找答案.毕竟一直 看视频也不是办法,不能形成自己的知识.于是想着看书汲 ... 
- python lambda表达式应用
			在python中有两种函数,一种是通过def得到的函数,一种是匿名函数,也就是lambda表达式.语法格式如下: lambda argument_list:expersion 语法中的argument ... 
- 【windows】【消息中间件】【安装】Elasticsearch
			一.准备工作 elasticsearch的下载地址:https://www.elastic.co/cn/downloads/elasticsearch ik分词器的下载地址:https://githu ... 
- ASP.NET Core 3.1 IOC容器以及默认DI以及替换Autofac生命周期
			IOC 就是我们需要一个对象 以前我们是去 new 现在我们是直接向 IOC容器 要我们需要的那个对象. 使用一个IOC容器(autofac)通过依赖注入控制各个组件的耦合.也就是说你写好了组件,不需 ... 
- root密码忘记了,怎么办?
			root是管理员使用的超级用户,如果密码忘记了,可以使用以下两种方法修改. 方法一: 进入单用户模式下进行密码修改 步骤1:重启系统,在系统进入3秒启动阶段,快速点击键盘上任意键可以取消默认进入系统状 ... 
