C++ 异常

概念

程序因硬件或代码编写时考虑不足导出的程序崩溃
硬件 : 不予处理
代码编写考虑不足 : 要处理
分类 :
编译时错误 : 因语法错误导致
运行时错误 : 考虑不足

抛出异常

关键字

throw:抛出

语法:

throw 数据;

throw 1;
throw 1.1;
throw 'c';
throw Person();
throw new Person();
...

捕获异常

语法

try
{
可能出现异常的代码
}
catch(数据类型1 变量名1)
{
}
catch(数据类型2 变量名2)
{
}
...

注意

如果try中出现异常代码,其try中剩余代码将不再执行,进入对应的catch中
catch中变量的值就是抛出异常时throw后的数据
catch可以有多个

栈解旋

概念

当try中出现异常,其异常代码之上创建的对象都会被释放
其释放顺序和创建顺序相反
这种情况称为栈解旋
注意:new创建的对象在堆区,无法自动释放

示例1

#include<iostream>

using namespace std;

class Date{

public:

Date(){

cout<<"Date 构造函数"<<endl;

}

~Date(){

cout<<"Date 析构函数"<<endl;

}

};

class Date02{

public:

Date02(){

cout<<"Date02 构造函数"<<endl;

}

~Date02(){

cout<<"Date02 析构函数"<<endl;

}

};

int main(int argc, char const *argv[])

{

try

{

Date *d01=new Date();

Date02 *d02=new Date02();

// Date02 d02;

// Date d01;

throw 1;

}

catch(int e)

{

cout<<"xxxx"<<endl;

}

return 0;

}
上面例子因为在堆区开辟,只能调取构造函数,无法析构
结果:

示例2(将示例1简单进行修改)

#include<iostream>

using namespace std;

class Date{

public:

Date(){

cout<<"Date 构造函数"<<endl;

}

~Date(){

cout<<"Date 析构函数"<<endl;

}

};

class Date02{

public:

Date02(){

cout<<"Date02 构造函数"<<endl;

}

~Date02(){

cout<<"Date02 析构函数"<<endl;

}

};

int main(int argc, char const *argv[])

{

try

{

// Date *d01=new Date();

// Date02 *d02=new Date02();

Date02 d02;

Date d01;

throw 1;

}

catch(int e)

{

cout<<"xxxx"<<endl;

}

return 0;

}

此时try在栈中构造函数,可以析构

结果:

异常的接口声明

语法

返回值类型 函数名(形参列表)throw(可能抛出的异常类型1,可能抛出的

异常类型2,...)

{

函数体

}

注意

如果throw()说明当前函数没有异常

throw()==noexcept关键字

示例

#include<iostream>

using namespace std;

//此时在VSCode会显示红色,但语法没有问题

void myDiv(int x,int y)throw(int,char)

{

if(y==0)

{

throw 1;

}

cout<<x/y<<endl;

}

int main(int argc, char const *argv[])

{

try

{

myDiv(10,0);

}

catch(int e)

{

cout<<"别理我"<<endl;

}

catch(char e)

{

cout<<"脑仁疼"<<endl;

}

return 0;

}

得到的结果为:别理我

异常对象的生命周期

情况1:传递异常对象

传递异常对象,此时会触发拷贝构造,形成一个新的异常对象,那么就得销毁这两个对象

示例

#include<iostream>

using namespace std;

class MyException

{

public:

MyException()

{

cout<<"构造函数被调用"<<endl;

}

MyException(const MyException& e)

{

cout<<"拷贝构造被调用"<<endl;

}

~MyException(){

cout<<"析构函数被调用"<<endl;

}

};

int main(int argc, char const *argv[])

{

try

{

//MyException():创建了一个MyException的一个对象,该对象没有对象名,称为匿名对象

throw MyException();

}

catch(MyException e)

{

}

return 0;

}

结果

情况2:传递异常对象指针

传递异常对象,创建一次,但是不销毁

示例

#include<iostream>

using namespace std;

class MyException

{

public:

MyException(){

cout<<"构造函数被调用"<<endl;

}

MyException(const MyException& e)

{

cout<<"拷贝函数被调用"<<endl;

}

~MyException(){

cout<<"析构函数被调用"<<endl;

}

};

int main(int argc, char const *argv[])

{

try

{

//传递的是指针

throw new MyException();

}

catch(MyException* e)

{

}

return 0;

}

结果

情况3:传递异常对象引用(建议使用)

传递异常对象引用,只会创建一次,而且可以自动销毁

示例

#include<iostream>

using namespace std;

class MyException

{

public:

MyException()

{

cout<<"构造函数被调用"<<endl;

}

MyException(const MyException& e)

{

cout<<"拷贝构造被调用"<<endl;

}

~MyException()

{

cout<<"析构函数被调用"<<endl;

}

};

int main(int argc, char const *argv[])

{

try

{

//传递的是异常对象的引用

throw MyException();

}

catch(MyException& e)

{

}

return 0;

}

结果

异常的多态

注意

1.抛出子类异常,可以被父类异常类型接收

2.抛出子类异常,catch中父类异常类型与子类异常类型,此时按代码书写顺序接收,

建议先子后父

示例

#include<iostream>

using namespace std;

class MyException{};

class NullException:public MyException{};

int main(int argc, char const *argv[])

{

try

{

throw NullException();

}

catch(NullException& e)

{

cout<<"NullException"<<endl;

}

catch(MyException& e)

{

cout<<"MyException"<<endl;

}

return 0;

}

结果

标准异常库

概述

由 C++ 提供的一套异常相关的类

自定义异常类

步骤

1, 定义一个类使其继承与 exception 或其子类
2, 定义一个变量记录异常信息
3, 定义该类的构造函数 , 拷贝构造 , 析构函数等
4, 重写 what 函数
const char* what() const noexcept
{
return 步骤 2 定义的变量 ;
}

注意

编译使用需加-std=c++11

相关推荐
西阳未落1 小时前
C语言中的内存函数(memcpy, memmove, memcmp, memset)
c语言·开发语言
axban3 小时前
QT M/V架构开发实战:QFileSystemModel介绍
开发语言·qt·架构
自动驾驶小卡4 小时前
boost::circular_buffer的使用方法简介
c++·boost·circular_buffer
钢门狂鸭5 小时前
关于rust的crates.io
开发语言·后端·rust
Lionel_SSL5 小时前
《深入理解Java虚拟机》第三章读书笔记:垃圾回收机制与内存管理
java·开发语言·jvm
睡不醒的kun6 小时前
leetcode算法刷题的第三十二天
数据结构·c++·算法·leetcode·职场和发展·贪心算法·动态规划
技术猿188702783516 小时前
PHP 与 WebAssembly 的 “天然隔阂”
开发语言·php·wasm
薄荷撞~可乐6 小时前
C#Task(Api)应用
开发语言·c#
范纹杉想快点毕业6 小时前
ZYNQ PS 端 UART 接收数据数据帧(初学者友好版)嵌入式编程 C语言 c++ 软件开发
c语言·笔记·stm32·单片机·嵌入式硬件·mcu·51单片机
乔宕一8 小时前
stm32 链接脚本没有 .gcc_except_table 段也能支持 C++ 异常
c++·stm32·嵌入式硬件