程序地带

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;
}
}
指针去接,结果为:
构造函数!
异常捕获!
析构函数!
*/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/gqw-myblogs/p/14286824.html

随机推荐

【已解决】video标签不会自动播放问题

今天在写一个视频组件的时候,写了autopaly但还是不会自动播放,于是我就去MDN上搜了一下,果真是找到了答案,MDN给出的解释如下图所示&#...

『业精于勤』 阅读(416)

一文掌握全部mysql面试题

一文掌握全部mysql面试题

1.mysql慢查询相关命令查看是否开启:showvariableslike'%slow_query%';查看慢查询判定时长:showvariablesli...

xiaohei_xiaobai 阅读(376)

iOS 多线程 NSOperation

 iOS开发当中,并发处理可能大家已经用惯了GCD的方式,今天我想聊一下NSOperation,因为相对来说,对于队列的操作相对灵活一些...

old__donkey 阅读(546)

LinkedHashSet

概述:​他是Set集合典型实现类HashSet的子类,继承了set集合的所有功能和特点,同时把其中的重要特点给修改,把无序变为有序。特点...

A丶Zeng 阅读(380)

【bug说】聊聊长沙的茶颜悦色跑去了武汉

最近长沙的茶颜悦色开到了武汉并且上了热搜,bug菌作为一个长沙人还是想在这里扯几句。话题描述#武汉茶颜悦色门外排起长队#,是这么回事,12月1日,...

最后一个bug 阅读(210)

css基础知识

奉天承运,博主诏曰:css基础知识CSS的概念行内样式代码:运行结果:内部样式表代码:运行结果:外部样式表代码&#x...

王十分 阅读(378)