「C/C++」C/C++异常处理

news/2024/11/22 13:58:30/

在这里插入图片描述

博客主页:何曾参静谧的博客
文章专栏:「C/C++」C/C++学习

目录

  • 相关术语
  • 一、C语言中的异常处理
    • 1.返回值来传递错误信息
    • 2.使用标准库函数对异常进行处理(不推荐)
    • 3.使用全局变量来记录错误信息(不推荐)
  • 二、C++中的异常处理
    • 1.try{}catch(){}异常处理
    • 2.C++标准的异常
    • 3.异常的重新解析(工程开发中比较实用)
    • 4.自定义异常类


相关术语

异常(Exception)处理:对程序运行时产生的异常进行处理。常见的异常如:计算异常、格式异常、内存不足异常、文件异常等。

一、C语言中的异常处理

C语言本身并没有提供内置的异常处理机制,但我们可以通过一些技巧来处理异常情况。
一般有两种方式进行处理:

  • 方法一:是通过返回值来传递错误信息
    例如在函数执行失败时返回一个特定的错误码,调用者可以根据返回值来判断函数是否执行成功并采取相应的处理方式。if()else()
  • 方法二:使用标准库函数对异常进行处理(不推荐)
    不推荐这种方法,暴力跳转导致代码可读性不高。
    assert()函数:用于在程序中检查一个条件是否成立,如果不成立,则中断程序并输出错误信息。
    setjmp()longjmp()函数:用于实现非局部跳转,在出现错误时跳转到事先设定的跳转点。
  • 方法三:是使用全局变量来记录错误信息(不推荐)
    这种方法不够安全,容易被其他代码改变这个全局变量的值,但是在一些简单的程序中可以使用。

1.返回值来传递错误信息

以下例子为一个除法的函数,当除数为0返回结果为-1

int divide(int a, int b, int* result) {const double eps = 1e-9;if (fabs(b) < eps) { // 除数为0,发生错误return 0; // 返回错误码0} else {*result = a / b; // 计算商return 1; // 返回成功码1}
}

2.使用标准库函数对异常进行处理(不推荐)

使用assert()函数进行处理

#include <assert.h>
#include <stdio.h>int main() {int a = 10, b = 0;assert(b != 0); // 如果b等于0,程序会中断执行,并输出错误信息int result = a / b;printf("%d / %d = %d", a, b, result);return 0;
}

使用setjmp()longjmp()函数进行处理

  • int setjmp(jmp_buf env)
    将当前上下文保持在jmp_buf结构体中
  • void longjmp(jmp_buf env, int val)
    jmp_buf结构体中恢复setjmp()保存的上下文
    最终从setjmp函数调用点返回,返回值为val
#include <setjmp.h>
#include <math.h>
#include <stdio.h>static jmp_buf env;double divide(int a, int b) {const double eps = 1e-9;double ret = 0;if (fabs(b) < eps) { // 除数为0,发生错误longjmp(env,1);} else {ret = a / b;}return ret;
}int main(int argc, char *argv[]){if(setjmp(env) == 0){double ret = divide(1,0);printf("r=%d", ret);}else{printf("除数为0");}
}

3.使用全局变量来记录错误信息(不推荐)

在多线程的环境下,全局变量可能会引起线程安全问题,因此在使用全局变量的时候需要注意线程同步问题。

二、C++中的异常处理

C++中的异常处理是一种程序控制流程的机制,用于处理程序运行时出现的异常情况,例如除以零、非法输入等等。通过使用异常处理,可以使程序在出现异常时不退出,而是能够优雅地处理异常,从而保证程序的可靠性稳定性

1.try{}catch(){}异常处理

C++中的异常处理机制主要包含以下几个关键字:

  • try:
    用于包含可能会抛出异常的代码块,对于可能抛出异常的代码需要放在try语句块中进行封装。
  • catch:
    用于捕获并处理由try块中抛出的异常,例如输出错误信息、恢复程序状态等等。可以有多个 catch 语句处理不同类型的异常。
    注意事项:
    1. 任何异常只会被catch捕捉一次。
    2. catch(...)只能在最后进行接受。
    3. 参数是严格匹配,不进行任何数据转换。
  • throw:
    用于在代码块中抛出异常,当程序在代码块中遇到了一个异常,就可以把这个异常抛出,交给try语句块之外的catch语句块进行处理。
//以下是示例代码:
#include <iostream>
#include <string>
#include <cmath>using namespace std;double divide(int a, int b) {const double eps = 1e-9;double ret = 0;if (fabs(b) < eps) { // 除数为0,发生错误throw 0;} else {ret = a / b;}return ret;
}int main(int argc, char *argv[]){try{double ret = divide(1,0);cout << "r=" << ret << endl;}catch(...){cout << "除数为0" << endl;}
}

2.C++标准的异常

需要包含标准的头文件:#inlcude <stdexcept>

异常名描述举例
标准异常这些异常是 C++ 标准定义的异常std::runtime_error、std::logic_error、std::out_of_range
输入输出异常这些异常通常都与输入输出操作相关std::ios_base::failure 和 std::bad_cast
内存异常这些异常通常与内存分配和释放操作相关std::bad_alloc 和 std::bad_array_new_length
数值计算异常这些异常通常与数值计算相关std::overflow_error、std::underflow_error
用户自定义异常这些异常由程序员自己定义继承std::exception
#include <iostream>
#include <stdexcept>double divide(double a, double b) {const double eps = 1e-9;double ret = 0;if (fabs(b) < eps) { // 除数为0,发生错误throw std::invalid_argument("除数为0,发生错误");} else {ret = a / b;}return ret;
}int main(){double a = 10, b = 0;try{int result = divide(a, b);std::cout << "结果: " << result << std::endl;}catch (std::exception& e){std::cerr << "异常捕捉: " << e.what() << std::endl;}return 0;
}

3.异常的重新解析(工程开发中比较实用)

常用于工程开发:当调用第三方库函数时,它本身已经有自己的异常处理机制但我们想用自己的异常处理时使用异常的重新解析。

//以下是一个示例代码,演示了如何对 `open` 函数进行异常转换:
#include <iostream>
#include <stdexcept>    // 包含 std::exception 等标准异常类
#include <fstream>      // 包含 open 函数
#include <string>class FileOpenFailed : public std::exception
{
public:FileOpenFailed(const std::string& fileName) : m_fileName(fileName) {}virtual const char* what() const noexcept{return ("Failed to open file: " + m_fileName).c_str();}private:std::string m_fileName;
};void openFile(const std::string& fileName)
{std::ifstream file;file.exceptions(std::ifstream::failbit);try{file.open(fileName);}catch(const std::ifstream::failure& e){// 捕获 std::ifstream::failure 异常throw FileOpenFailed(fileName);     // 转换为我们自己定义的异常并抛出}// 执行文件操作...
}int main(){try{openFile("nonexistent.txt");}catch(const std::exception& e){// 捕获我们自己定义的异常std::cerr << e.what() << '';return -1;}// ...return 0;
}

4.自定义异常类

#include <iostream>
#include <exception>
#include <string>class MyException : public std::exception
{
public:MyException(const char* message) : msg(message) {}const char* what() const throw() { return msg.c_str(); }
private:std::string msg;
};void divide(int x, int y){if (y == 0) {throw MyException("Division by zero");}std::cout << "Result: " << x / y << std::endl;
}int main(){try {divide(10, 2);divide(10, 0);} catch (MyException& e) {std::cout << "Exception caught: " << e.what() << std::endl;}return 0;
}

在这里插入图片描述


http://www.ppmy.cn/news/49336.html

相关文章

【数据结构实验】约瑟夫环

数据结构实验—约瑟夫环 简介 分别利用线性表的顺序存储形式和链式存储形式&#xff0c;按照出列的顺序印出各人的编号。文末贴出了源代码 需求分析 每个人的数据m需要随机产生&#xff0c;可正可负且不是实现存储的&#xff0c;这意味着需要使用随机函数来生成每个人的数据…

redis设计与实现读书笔记(2)

今天看的是关于单机数据库&#xff0c;RDB持久化以及AOF持久化的内容。 关于单机数据库 1.默认数据库数量 redis的服务器默认是会创建16个数据库&#xff0c;每个客户端访问的时候都要指定自己的目标数据库。 select可以切换目标数据库。 注意事项 到目前为止&#xff0c…

瓷器:伟大发明的特点和能量的作用

文章目录 引言I 瓷器的独特性1.1 用途特别大。1.2 影响力广泛,经济意义大1.3 难以替代性。1.4 瓷器的发明特别难II 上釉2.1 上釉方法2.2 发明和发现的区别III 发明的必然性和偶然性3.1 偶然性3.2 偶然性的背后常常有着必然性。3.3 一种技术会抑制另一种技术引言 从预先要求和…

数据库方言:了解不同数据库系统的特性和差异

摘要&#xff1a; 数据库方言指的是不同数据库系统在 SQL 语法和实现上的差异。本文将探讨数据库方言的概念、为什么会存在方言、常见数据库方言的特点以及如何处理方言差异。 1. 什么是数据库方言&#xff1f; 数据库方言是指不同数据库系统在 SQL 语法、数据类型、函数和存…

软考 - IP地址与网络划分

一.IP组成 1.1 首个八位字节规则 1.2 地址掩码 IP地址掩码 标准地址掩码 A类&#xff1a;255.0.0.0 前1个字节是网络号 后3个字节是主机号 B类&#xff1a;255.255.0.0 前2个字节是网络号 后2个字节是主机号 C类&#xff1b;255.255.255.0 前3个字节是网络号 后1个字节是主机号…

赛效:怎么用改图鸭进行一键Logo设计?

改图鸭工具是一款在线图像处理工具&#xff0c;可以对图片进行大小调整、添加色彩、滤镜等&#xff0c;用户使用改图鸭可快速轻松地对多种图像进行处理操作&#xff0c;另外&#xff0c;改图鸭工具还支持一键进行Logo设计&#xff0c;很多人对改图鸭工具比较陌生&#xff0c;不…

【头歌C语言程序设计】结构体解答

写在前面 这道题总体来说还是偏难的&#xff0c;如果只看代码比较难以理解&#xff0c;当结构体的文章发出后&#xff0c;就有许多小伙伴问我这个问题&#xff0c;我开始意识到&#xff0c;可能我对这道题所作的解答还不够&#xff08;不装了&#x1f601;&#xff0c;根本没有…

揭秘移动云大会展区前沿科技

2023年4月25日-26日 我们苏州金鸡湖国际会议中心见&#xff01; 1场重磅主论坛、10场分论坛、2600㎡展区 数字中国新未来 尽在2023移动云大会 2023移动云大会设有中国移动和合作伙伴两大展区&#xff0c;联合40余家优质合作伙伴&#xff0c;全方位展示移动云在自主能力、行…