2023-5-22-C++异常处理机制学习

news2024/12/17 17:48:24


🍿*★,°*:.☆( ̄▽ ̄)/$:*.°★* 🍿

💥💥💥欢迎来到🤞汤姆🤞的csdn博文💥💥💥
💟💟喜欢的朋友可以关注一下,下次更新不迷路💟💟
😆😆😆私聊获取个人订阅号哦,欢迎订阅共同学习😆😆😆
💖💖💖💖可以加入大家庭群聊,一起学习天天有福利💖💖💖💖





🍬本文摘要

在这里插入图片描述

这篇文章是为了多角度学习一下C++异常处理机制,打算后续写一个高级全面的日志管理工具。


目录

  • 🍬本文摘要
  • 😉一、C++异常处理机制介绍
  • 🎉二、抛出和捕获异常的方式
  • 🎉三、C++异常有几种
  • 🐱‍🚀四、标准C++异常有几种
  • 🎂五、怎么实现自定义异常
  • 🥩六、注意事项
  • 🍚七、什么是异常安全性?如何保证程序具有异常安全性?
  • 🥠八、RAII技术在异常处理中的应用
  • 🍚九、std::exception_ptr的作用和使用方法
  • 🍳参考文献
  • 🧊文章总结



😉一、C++异常处理机制介绍

C++ 异常处理机制是一种用于在程序运行时检测错误并进行相应处理的技术。当程序执行过程中遇到异常情况,比如计算错误、内存分配失败等,就会抛出一个异常对象。该对象包含有关异常的信息,包括异常类型和位置。

异常处理机制是由 try-catch 块组成的。try 块中包含可能引发异常的代码,而 catch 块则用于处理特定类型的异常。可以为每个 try 块指定多个 catch 块,以便处理不同类型的异常。

当 try 块中的代码引发异常时,控制流将转移到与之匹配的 catch 块。如果没有匹配的 catch 块,则程序将终止,并显示错误消息。

除了 try-catch 块外,还有一些其他的异常处理机制,例如 throw 操作符和 noexcept 关键字。throw 操作符用于抛出异常,而 noexcept 关键字用于指示函数不会抛出异常。这些机制可以更精细地控制异常处理过程。

需要注意的是,在使用异常处理机制时,需要小心确保资源的正确释放,以避免内存泄漏等问题。

try {
    // 可能抛出异常的代码
} catch (exception& e) {
    // 处理异常
}


🎉二、抛出和捕获异常的方式

在 C++ 中,抛出和捕获异常的方式主要有以下两种:

  1. 使用 try-catch 块:try 块中包含可能引发异常的代码,而 catch 块则用于处理特定类型的异常。可以为每个 try 块指定多个 catch 块,以便处理不同类型的异常。

示例代码:

try {
    // 可能会引发异常的代码
    throw MyException();  // 抛出自定义异常
}
catch (MyException& e) {  // 处理自定义异常
    // 处理异常的代码
}
catch (std::exception& e) {  // 处理标准异常
    // 处理异常的代码
}
catch (...) {  // 处理所有其他异常
    // 处理异常的代码
}
  1. 使用 throw 操作符:throw 操作符用于抛出异常。通过 throw 抛出的异常可以被上层调用者捕获并处理。

示例代码:

if (someCondition) {
    // 抛出 std::runtime_error 异常
    throw std::runtime_error("An error occurred.");
}

🎉三、C++异常有几种

C++ 异常主要可以分为三种类型:

  1. 标准异常(std::exception):是所有标准 C++ 异常的基类,包括 std::runtime_error、std::logic_error 等。

  2. 自定义异常:程序员可以根据自己的需求创建异常类来实现特定的异常处理逻辑。

  3. 系统异常:由操作系统或底层库抛出的异常,例如访问非法内存地址、除零等。这些异常不能被捕获并处理,只能通过遵循编程最佳实践避免它们的发生。


🐱‍🚀四、标准C++异常有几种

标准C++异常有15种,其中13种是派生自std::exception的标准异常类,另外两种是std::bad_exception和std::nested_exception。

这些标准异常类的区别在于它们所表示的错误类型不同。例如,std::invalid_argument异常表示对一个函数传递了无效的参数,而std::out_of_range异常则表示访问了一个超出范围的元素。std::bad_alloc异常表示内存分配失败,而std::logic_error异常表示程序逻辑错误。以下是15中标准C++异常:
以下是 C++ 标准库中 15 种标准异常及其含义:

  1. std::exception:所有标准异常的基类,可以被用来捕获任意一个标准异常。
  2. std::bad_alloc:在动态内存分配失败时抛出。
  3. std::bad_cast:在使用动态类型转换(dynamic_cast)时,如果转换目标与对象类型不兼容,则抛出。
  4. std::bad_exception:当函数抛出了一个未捕获的异常时,会调用 std::unexpected() 函数,如果 std::unexpected() 函数也抛出了异常,则会进一步调用 std::terminate() 函数。std::bad_exception 就是 std::unexpected() 函数抛出的异常。
  5. std::bad_typeid:在使用 typeid 运算符获取对象类型信息时,如果对象是空指针或者不是多态类型,则会抛出此异常。
  6. std::logic_error:逻辑错误,通常在程序运行期间检测到。从 std::exception 继承而来,有两个子类:std::domain_error 和 std::invalid_argument。
  7. std::domain_error:某些操作的参数超出了定义域范围。
  8. std::invalid_argument:提供给函数的参数无效。
  9. std::length_error:当试图创建大于 max_size 的对象时抛出。
  10. std::out_of_range:访问数组、字符串或容器等序列类型时,下标越界时抛出。
  11. std::runtime_error:运行时错误,通常在程序运行期间检测到。从 std::exception 继承而来,有四个子类:std::overflow_error、std::range_error、std::underflow_error 和 std::system_error。
  12. std::overflow_error:算术上溢出(如整数相加结果超过了类型的最大值)时抛出。
  13. std::range_error:尝试存储超过类型所能表示的数据(如负数开根号)时抛出。
  14. std::underflow_error:算术下溢(如整数相减结果超过了类型的最小值)时抛出。
  15. std::system_error:涉及底层操作系统或者 C++ 标准库的错误,比如文件打开失败等。含有一个 error_code 类型的成员变量表示错误码。

std::bad_exception和std::nested_exception是除标准异常以外的两个特殊异常类。std::bad_exception用于表示抛出了一个未知的异常类型,而std::nested_exception用于捕获、保存并再次抛出当前异常的信息。


🎂五、怎么实现自定义异常

在 C++ 中,可以通过继承标准异常类 std::exception 来实现自定义异常。具体步骤如下:

  1. 定义一个新的异常类,并从 std::exception 继承。
class MyException : public std::exception {
public:
    // 构造函数可以接受一个字符串作为异常信息
    MyException(const std::string& msg) : message(msg) {}

    // 继承自 std::exception 的虚函数 what(),用于返回异常信息
    const char* what() const noexcept override {
        return message.c_str();
    }

private:
    std::string message;
};
  1. 抛出自定义异常对象。
void foo() {
    throw MyException("Something went wrong!");
}
  1. 在 catch 块中捕获自定义异常。
try {
    foo();
} catch (const MyException& e) {
    std::cerr << "Exception caught: " << e.what() << '\n';
}

在这个例子中,我们定义了一个名为 MyException 的异常类,它包含一个字符串类型的成员变量 message 用于存储异常信息。该类同时重载了 what() 函数,以便在抛出异常时提供异常信息。

在函数 foo() 中,我们使用 throw 语句抛出一个 MyException 类型的对象并传递一个字符串作为异常信息。

try-catch 块中,我们编写了一个 catch 块来捕获 MyException 类型的异常,打印出异常信息。


🥩六、注意事项

以下是在C++中处理异常时需要注意的事项:

  1. 在程序中使用try-catch块捕获异常,避免程序因未处理的异常而崩溃。
  2. 异常应该被抛出和捕获在适当的位置,即在能够处理它们的地方抛出异常,然后在合适的位置进行捕获。
  3. 不要在析构函数中抛出异常,因为这可能导致未定义的行为。
  4. 使用特定的异常类型来组织代码,并且仅在必要的情况下派生新的异常类型。
  5. 将异常信息记录到日志文件中,以便更好地跟踪异常发生的原因。
  6. 不要在循环中捕获异常,因为这会影响程序的性能。
  7. 避免在同一try块中嵌套多个catch块,因为这可能会使代码变得混乱难懂。
  8. 在尝试修复异常之前,请确保已经详细了解了异常的根本原因。
  9. 不要忽略异常,即使它们似乎可以安全地被忽略。这可能导致程序在后续执行中出现问题。
  10. 小心处理内存分配的异常,如果没有正确的处理,这可能导致内存泄漏或其他严重的问题。

这些是处理C++异常时需要注意的一些重要事项,但并不是全部。处理异常时最重要的原则是谨慎和小心,以确保程序的安全性和稳定性。


🍚七、什么是异常安全性?如何保证程序具有异常安全性?

在C++中,异常安全性是指一个程序在发生异常后仍能保持正确和健壮的行为。具有良好的异常安全性意味着即使出现异常,程序也不会崩溃或导致资源泄漏等问题。

要确保程序具有异常安全性,可以采取以下措施:

  1. 使用RAII(Resource Acquisition Is Initialization)技术来管理资源,例如使用智能指针、容器和文件句柄等。这些资源对象在其析构函数中释放资源,无论是否发生异常。

  2. 避免手动管理内存,使用标准库容器、字符串和算法等高级语言特性进行操作。

  3. 在抛出异常时不要改变对象状态,因为这可能导致未定义的行为。可使用copy-and-swap技术避免状态的改变。

  4. 将资源分配和使用的代码块封装在单独的函数中,并将其声明为noexcept,这样可以确保该函数不会引发异常

  5. 在处理异常时,必须对所有可能引发异常的代码进行评估,并在恢复正常执行之前确保任何资源都已正确释放。

  6. 在编写代码时,考虑到异常情况并进行适当的测试。

通过以上措施可以提高程序的异常安全性,在开发大型项目时,保持良好的异常安全性对于代码的可维护性和稳定性至关重要。


🥠八、RAII技术在异常处理中的应用

RAII(Resource Acquisition Is Initialization)技术是一种C++编程技术,它通过在对象的构造函数中获取资源并在析构函数中释放资源来管理资源。

在异常处理中,RAII技术可以确保资源在出现异常时被正确地释放。当抛出异常时,程序会自动执行已经创建的对象的析构函数,从而释放对象占用的资源,无需手动处理异常。这种自动化的行为避免了可能发生的资源泄漏和内存泄漏问题。通常情况下,RAII技术与C++标准库中的智能指针结合使用,以确保动态分配的内存得到正确地释放。

例如,在操作文件时,我们可以使用std::ofstream来打开文件,并将其封装在一个类中:

class File {
public:
    File(const std::string& filename) : _file(filename) {
        if (!_file.is_open()) {
            throw std::runtime_error("failed to open file");
        }
    }

    ~File() {
        if (_file.is_open()) {
            _file.close();
        }
    }

    void write(const std::string& s) {
        _file << s;
    }

private:
    std::ofstream _file;
};

void foo() {
    File f("test.txt");
    f.write("hello, world");
}

int main() {
    try {
        foo();
    } catch (std::exception& e) {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

在上面的示例中,我们定义了一个File类来封装文件操作,构造函数中打开文件并检查是否成功打开,析构函数中关闭文件。

在foo函数中,我们创建了一个File对象来进行文件写操作。无论在写入数据时是否发生异常,File对象都会被正确地销毁,并自动调用析构函数来关闭文件。这保证了程序具有异常安全性。

总之,RAII技术能够有效地提高代码的可靠性和可读性,使得程序的异常处理更加简单和安全。


🍚九、std::exception_ptr的作用和使用方法

std::exception_ptr是一个指向异常的指针,它允许将异常在程序的不同部分传递和保存,从而实现跨越不同层次的异常处理。

使用方法如下:

  1. 在抛出异常时使用 std::make_exception_ptr()std::current_exception() 函数创建 std::exception_ptr 对象。
  2. std::exception_ptr 作为参数传递给其他函数或对象以传递异常信息。
  3. 在需要重新抛出异常时,可以使用 std::rethrow_exception() 函数将 std::exception_ptr 转换回原始的异常对象。
  4. 在捕获异常时,可以使用 std::exception_ptr 指示是否发生了异常,并使用 std::rethrow_if_nested() 函数检查是否存在嵌套异常。

例如,以下代码演示了如何使用 std::exception_ptr 来传递异常信息:

void foo() {
    try {
        // some code that may throw an exception
    } catch (...) {
        std::exception_ptr eptr = std::current_exception();
        bar(eptr); // pass the exception to another function
    }
}

void bar(std::exception_ptr eptr) {
    if (eptr) {
        // rethrow the exception
        std::rethrow_exception(eptr);
    } else {
        // handle the case where no exception was thrown
    }
}

🍳参考文献

🧊文章总结

提示:这里对文章进行总结:

  本文讲了关于C++异常处理机制的一些内容,希望大家有所收获。






更多好文推荐

🍸2021-4月Python 机器学习——中文新闻文本标题分类
🍹2021年4月-(计算机网络)小型校园网络模拟搭建,最全最准确版
🍺2022-10-31-基于用户的协同过滤推荐算法实现+MAE+RMSE
🍻2022-11-28-大数据可视化,特征维度大于50
🥂2023-3-9-一篇简短的文章把C++左右值关系讲的透透彻彻

上一篇
End
下一篇

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/554992.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go语言核心编程-函数、包和错误处理

第 6 章 函数、包和错误处理 6.1 为什么需要函数 6.1.1请大家完成这样一个需求: 输入两个数,再输入一个运算符(,-,*,/)&#xff0c;得到结果.。 6.1.2使用传统的方法解决 走代码 分析一下上面代码问题 上面的写法是可以完成功能, 但是代码冗余同时不利于代码维护函数可以解…

跟卖又被“抄家”了,亚马逊新手要怎么做?

今天网上看到又有一家跟卖的被砸了&#xff0c;图片大致是下面这样的&#xff08;网上找的图&#xff0c;跟我看到的图片类似&#xff09;。 图片下方还有几句话&#xff1a;“事已办完&#xff0c;跟卖的窝点被我端了&#xff01;” 然后整个群里是一片欢腾&#xff0c;各种“…

网络安全是一个好专业吗

前言 网络安全作为一个专业领域&#xff0c;在当今数字时代正变得越发重要和关键。无论是企业还是个人&#xff0c;面对着越来越频繁的网络威胁和攻击&#xff0c;网络安全领域的专业人员扮演着至关重要的角色。那么&#xff0c;从一个资深网安工程师的角度来看&#xff0c;网…

SpringBoot——Bean属性绑定

简单介绍&#xff1a; 之前我们介绍过我们如何在Bean中获取配置文件的方式&#xff0c;就是通过将类注册到Spring容器中&#xff0c;然后通过ConfigurationProperties()注解&#xff0c;这个注解有一个参数叫做prefix&#xff0c;参数的值就是我们在配置文件中配置的一组数据的…

成为移动测试高手!本文教你掌握移动APP测试的关键知识和技巧,提升测试水平,轻松获取高薪工作!(上)

目录 引言 首先搭建android-sdk环境 一.兼容性测试【原生APP】 1.WEB 2.APP 2.1操作系统 2.2分辨率 2.3不同厂家 2.4网络类型 (1)h5小程序类型&#xff1a; 如何测试APP在不同手机的情况 如何测试弱网络 &#xff08;2&#xff09;.小程序 二.功能测试点 (另外)…

备战2023年秋招,一套吃透全部技术栈.....

今天跟大家分享这份测试工程师全套面试攻略包含了软件测试基础 、MySQL基础、Liunx、web测试、接口测试、App测试、Python、selenium、管理工具、性能测试、LordRunner、计算机网络、组成原理、数据结构与算法、ab测试等。这些都是我在各个大厂总结出来的面试真题&#xff0c;很…

SSM框架-Spring的学习

1.Spring简介 Spring是什么&#xff08;理解&#xff09; 官网地址: https://spring.io/ ​ Spring框架由Rod Johnson开发&#xff0c;2004年发布了Spring框架的第一版。Spring是一个从实际开发中抽取出来的框架&#xff0c;因此它完成了大量开发中的通用步骤&#xff0c;留给…

多个Filter的执行顺序 | 职责链模式应用

文章目录 前言一、多个Filter的执行顺序实操1. 配置web.xml方式注册Filter结论&#xff1a; 2. 注解方式注册Filter结论&#xff1a; 二、职责链模式的应用1. 回顾职责链模式2. Filter职责链模式的应用 总结 前言 Filter(过滤器) 是 Java Servlet 规范中定义的一种组件&#xf…

【计算机组成】三分钟了解顺序存储、直接存储、随机存储和相联存储的区别

一.按地址访问和按内容访问的区别 按地址访问&#xff08;顺序存储、直接存储和随机存储&#xff09;&#xff1a;我知道这个数据存在哪个地址中&#xff0c;现在我把这个地址给你&#xff0c;麻烦你帮我找出我要的数据来 按内容访问&#xff08;相联存储&#xff09;&#xff…

Netty编解码机制(一)

1.编码和解码基本介绍 1>.编写网络应用程序时,因为数据在网络中传输的都是二进制字节码数据,在发送数据时就需要编码,接收数据时就需要解码; 2>.codec(编解码器)的组成部分有两个: decoder(解码器)和 encoder(编码器).encoder(编码器)负责把业务数据转换成字节码数据,而…

BurpSuite—-Scanner模块(漏洞扫描)

本文主要BurpSuite—-Scanner模块(漏洞扫描)介绍的相关内容 关于BurpSuite的安装可以看一下之前这篇文章&#xff1a; http://t.csdn.cn/cavWt 一、简介 Burp Scanner 是一个进行自动发现 web 应用程序的安全漏洞的工具。它是为渗透测试人员设计的&#xff0c;并且它和你现有…

Revit幕墙:这些命令在幕墙嵌板中的妙用及快速幕墙

一、Revit中这些命令在幕墙嵌板中的妙用 在我们做幕墙时&#xff0c;通常会有不同种类的幕墙&#xff0c;比如材质不同&#xff0c;颜色不同。这时我们就需要去选中嵌板进行替换新样式的嵌板。 1.通常我们在替换嵌板时都是通过Tab切换&#xff0c;然后选中嵌板。这样进行来回切…

windows免费版切割pdf拆分pdf提取pdf指定页码小工具

如图所示&#xff1a;选择pdf文件&#xff0c;输入指定页码区间&#xff0c;使用逗号分隔&#xff0c;逗号不区分中英文。如输入1-10&#xff0c;11-20&#xff0c;21-21&#xff0c;点击开始分割&#xff0c;会拆分出1-10.pdf&#xff0c;11-20.pdf&#xff0c;21-21.pdf&…

短视频矩阵源码-智能剪辑生成技术数值组如何编程?

短视频混剪生成时长逻辑一般采用根据用户设定的总时长、视频数量、时长比例等参数计算出每个视频在混剪中所占的时长&#xff0c;然后根据视频的总时长与所占比例来划分每个视频在混剪中的时长&#xff0c;最后将各个视频拼接起来形成混剪视频。此算法可以进行灵活的时长调整和…

rt下降40%?程序并行优化六步法 | 京东云技术团队

1 背景 性能优化是我们日常工作中很重要的一部分&#xff0c;主要有以下原因&#xff1a; 降低服务器和带宽等硬件成本&#xff1a;用更少的资源处理更多的请求提高现实世界的运行效率&#xff1a;人机处理效率存在数量级的偏差&#xff0c;同样机器世界的效率提升能带来现实…

十一、配置内网穿透实现消息模块和授权登陆模块

开通内网穿透的服务&#xff08;后端8333&#xff0c;前端8080&#xff09;&#xff1a; 启动内网穿透服务&#xff1a; 创建CourseApiController来实现关键词查询课程信息&#xff1a; package com.lxl.ggkt.vod.api;import com.baomidou.mybatisplus.core.conditions.query.…

2023年认证杯SPSSPRO杯数学建模D题(第一阶段)立体车库的自动调度问题全过程文档及程序

2023年认证杯SPSSPRO杯数学建模 D题 立体车库的自动调度问题 原题再现&#xff1a; 随着人们生活水平的提高&#xff0c;汽车保有量日益增加&#xff0c;而城市土地资源有限&#xff0c;传统平面停车场土地面积利用率低, 这样便形成了交通拥挤、停车困难的现象。为解决该问题…

资深测试老鸟整理,超全自动化测试用例详解-小技巧总结...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 Python自动化测试&…

PCA的数学原理和python实现

最近学习了一下PCA&#xff0c;具体原理网址如下&#xff1a; CodingLabs - PCA的数学原理 主要原理是通过线性变换将原始数据变换为一组各维度线性无关的表示&#xff0c;其中将方差最大的方向作为主要特征。提取数据的主要特征分量&#xff0c;可用于高维数据的降维 主要算…

工作3年裸辞,从18K到38K,面试也····

现在的面试好像也不是那么的难 工作3年&#xff0c;换了好几份工作&#xff08;行业流行性大&#xff09;&#xff0c;每次工作都是裸辞。朋友都觉得不可思议。因为我一直对自己很有信心&#xff0c;而且特别不喜欢请假面试&#xff0c;对自己负责也对公司负责。 但是这次没想…