当前位置: 首页 > news >正文

技术学习笔记 1:C++标准库异常类(c++中怎样用自己错误信息交给try catch捕获)

`throw std::runtime_error("链接数据库失败.");`

技术学习笔记:C++标准库异常类

1. C++异常处理机制概述

C++的异常处理机制允许程序在遇到错误时,能够以一种结构化的方式进行错误处理。异常处理包括三个主要部分:抛出(throw)、捕获(catch)和处理(handle)。

2. 标准异常类std::exception

所有标准异常类都继承自std::exception,它提供了一个虚函数what(),返回一个C风格字符串,描述了异常的原因。

示例代码:

try {throw std::exception("基础异常");
} catch (const std::exception& e) {std::cerr << "异常信息: " << e.what() << std::endl;
}

3. 运行时异常std::runtime_error

用于表示程序运行时遇到的意外情况,如文件找不到、内存不足等。

示例代码:

try {throw std::runtime_error("运行时错误:文件未找到");
} catch (const std::runtime_error& e) {std::cerr << "运行时错误: " << e.what() << std::endl;
}

4. 逻辑异常std::logic_error

用于表示程序内部逻辑错误,比如违反了程序的预设条件。

示例代码:

try {throw std::logic_error("逻辑错误:无效操作");
} catch (const std::logic_error& e) {std::cerr << "逻辑错误: " << e.what() << std::endl;
}

5. 其他标准异常类

以下是C++标准库中提到的异常类的具体使用示例:

5.1 std::bad_exception

std::bad_exception通常不是直接抛出的,而是当标准异常处理机制遇到问题时由编译器抛出。

示例代码:

try {throw; // 重新抛出当前异常
} catch (...) {throw std::bad_exception(); // 抛出std::bad_exception
}

5.2 std::bad_alloc

当内存分配失败时,例如使用new操作符时,会抛出此异常。

示例代码:

try {throw std::bad_alloc(); // 模拟内存分配失败
} catch (const std::bad_alloc& e) {std::cerr << "内存分配失败: " << e.what() << std::endl;
}

5.3 std::bad_cast

当使用dynamic_cast进行向下转型失败时,会抛出此异常。

示例代码:

class Base {
public:virtual ~Base() {}
};class Derived : public Base {
};try {Base* base = new Derived();Derived* derived = dynamic_cast<Derived*>(base);if (!derived) {throw std::bad_cast(); // 模拟类型转换失败}delete base;
} catch (const std::bad_cast& e) {std::cerr << "类型转换失败: " << e.what() << std::endl;
}

5.4 std::bad_typeid

当使用typeid操作符并且操作失败时,会抛出此异常。这种情况很少发生,因为typeid操作符通常不会失败。

示例代码:

try {// 模拟typeid操作失败的情况throw std::bad_typeid();
} catch (const std::bad_typeid& e) {std::cerr << "typeid操作失败: " << e.what() << std::endl;
}

5.5 std::domain_error

当函数的参数值不在有效域内时,可以抛出此异常。

示例代码:

try {double x = -1.0;if (x < 0) {throw std::domain_error("负数不在有效域内");}
} catch (const std::domain_error& e) {std::cerr << "域错误: " << e.what() << std::endl;
}

5.6 std::invalid_argument

当传递给函数的参数无效时,可以抛出此异常。

示例代码:

try {std::string arg = "";if (arg.empty()) {throw std::invalid_argument("参数不能为空");}
} catch (const std::invalid_argument& e) {std::cerr << "无效参数: " << e.what() << std::endl;
}

5.7 std::length_error

当容器无法分配请求的长度时,会抛出此异常。

示例代码:

try {std::vector<int> v(1000000000); // 尝试分配大量内存
} catch (const std::length_error& e) {std::cerr << "长度错误: " << e.what() << std::endl;
}

5.8 std::out_of_range

当索引或迭代器超出容器的界限时,会抛出此异常。

示例代码:

try {std::vector<int> v = {1, 2, 3};v.at(5); // 尝试访问不存在的索引
} catch (const std::out_of_range& e) {std::cerr << "索引越界: " << e.what() << std::endl;
}

5.9 std::overflow_error

当发生算术溢出时,可以抛出此异常。

示例代码:

try {int a = std::numeric_limits<int>::max();a++; // 导致溢出
} catch (const std::overflow_error& e) {std::cerr << "溢出错误: " << e.what() << std::endl;
}

5.10 std::range_error

当数值范围错误时,可以抛出此异常。

示例代码:

try {double sqrt_input = -1.0;sqrt(sqrt_input); // 尝试计算负数的平方根
} catch (const std::range_error& e) {std::cerr << "范围错误: " << e.what() << std::endl;
}

请注意,这些示例代码中的异常抛出是为了演示目的,实际使用中可能需要根据具体情况进行调整。

通用异常处理示例代码:

#include <stdexcept>
#include <new> // For std::bad_alloc
#include <typeinfo> // For std::bad_casttry {// 模拟不同类型的异常抛出throw std::out_of_range("索引越界");// ... 其他异常
} catch (const std::exception& e) {std::cerr << "捕获到标准库异常: " << e.what() << std::endl;
}

6. 自定义异常类

除了使用标准库中的异常类,开发者也可以根据需要定义自己的异常类,以携带更多的错误上下文信息。

示例代码:

class MyException : public std::exception {
public:const char* what() const throw() {return "自定义异常";}
};try {throw MyException();
} catch (const std::exception& e) {std::cerr << "捕获到自定义异常: " << e.what() << std::endl;
}

7. 异常处理的最佳实践

  • 异常应该用于处理预期之外的错误情况。
  • 避免在频繁执行的代码路径中使用异常,因为这可能会影响性能。
  • 尽量使用标准库异常类,但在需要时定义自定义异常类。
  • 确保异常安全,即在异常发生时,程序的状态应该是一致的。

实际操练

以下是一个使用C++异常处理机制的完整示例程序。这个程序演示了如何定义一个自定义异常类,抛出和捕获不同类型的异常,并展示了异常处理的最佳实践。

#include <iostream>
#include <vector>
#include <stdexcept>// 自定义异常类
class CustomException : public std::exception {
private:std::string message;
public:CustomException(const std::string& msg) : message(msg) {}virtual const char* what() const throw() {return message.c_str();}
};// 模拟一个可能抛出异常的函数
int divide(int numerator, int denominator) {if (denominator == 0) {throw CustomException("除数不能为零");}return numerator / denominator;
}// 另一个可能抛出异常的函数
void processElement(const std::vector<int>& elements, size_t index) {if (index >= elements.size()) {throw std::out_of_range("索引超出范围");}std::cout << "处理元素: " << elements[index] << std::endl;
}int main() {try {// 尝试除以零std::cout << "尝试除以零的结果: " << divide(10, 0) << std::endl;} catch (const CustomException& e) {std::cerr << "捕获到自定义异常: " << e.what() << std::endl;} catch (const std::exception& e) {std::cerr << "捕获到标准异常: " << e.what() << std::endl;}try {std::vector<int> elements = {1, 2, 3};// 尝试访问不存在的元素processElement(elements, 5);} catch (const std::out_of_range& e) {std::cerr << "捕获到索引越界异常: " << e.what() << std::endl;} catch (const std::exception& e) {std::cerr << "捕获到其他标准异常: " << e.what() << std::endl;}return 0;
}

程序说明:

  1. 自定义异常类CustomException继承自std::exception,用于表示自定义的错误情况。
  2. 可能抛出异常的函数divide函数在尝试除以零时抛出CustomException异常;processElement函数在尝试访问数组越界时抛出std::out_of_range异常。
  3. 异常捕获:在main函数中,我们使用两个try-catch块来捕获和处理这些异常。第一个try-catch块捕获divide函数可能抛出的异常,第二个try-catch块捕获processElement函数可能抛出的异常。
  4. 异常处理:在catch块中,我们使用what()方法来获取异常的描述信息,并将其输出到标准错误流。

这个示例程序演示了如何使用C++的异常处理机制来处理程序中的错误情况,包括自定义异常和标准库异常。通过这种方式,我们可以在不中断程序正常流程的情况下优雅地处理错误。


分享一个有趣的 学习链接

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 餐饮连锁加盟的网页UI,如果不大气,谁能相信你的品牌力
  • Package.Json 参数配置理解用途
  • C:关于位操作符:、|、^、~的一些应用
  • 百日筑基第三十七天-阿里开发手册编程规约
  • 编程实践|如何用 MoonBit 实现 diff(三)
  • 使用css在照片右上角设置缎带效果
  • 请以零基础学Python 之 第二十讲 分组和贪婪匹配
  • 从新手到高手:Scala函数式编程完全指南,Scala 文件 I/O(27)
  • 【LLM】-10-部署llama-3-chinese-8b-instruct-v3 大模型
  • 类似redmine的项目管理系统有哪些?10款软件测评
  • 基础跟张宇,强化换武忠祥可行吗?会不会漏什么?
  • Flask目录结构路由重定向简单实例讲解——轻量级的 Python Web 框架
  • 【数据结构】——堆的实现与算法
  • ElasticSearch父子索引实战
  • 怎么用U盘重装系统
  • 【Leetcode】101. 对称二叉树
  • 【Linux系统编程】快速查找errno错误码信息
  • canvas 绘制双线技巧
  • HashMap剖析之内部结构
  • java多线程
  • jquery ajax学习笔记
  • niucms就是以城市为分割单位,在上面 小区/乡村/同城论坛+58+团购
  • tensorflow学习笔记3——MNIST应用篇
  • TypeScript实现数据结构(一)栈,队列,链表
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • 从零开始学习部署
  • 翻译 | 老司机带你秒懂内存管理 - 第一部(共三部)
  • 个人博客开发系列:评论功能之GitHub账号OAuth授权
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 关于Android中设置闹钟的相对比较完善的解决方案
  • 那些年我们用过的显示性能指标
  • 适配mpvue平台的的微信小程序日历组件mpvue-calendar
  • 数据结构java版之冒泡排序及优化
  • 写代码的正确姿势
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • ​Spring Boot 分片上传文件
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • #1014 : Trie树
  • #QT(QCharts绘制曲线)
  • #我与Java虚拟机的故事#连载03:面试过的百度,滴滴,快手都问了这些问题
  • #我与Java虚拟机的故事#连载05:Java虚拟机的修炼之道
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • ( 10 )MySQL中的外键
  • (13)Hive调优——动态分区导致的小文件问题
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (二)【Jmeter】专栏实战项目靶场drupal部署
  • (二)学习JVM —— 垃圾回收机制
  • (简单) HDU 2612 Find a way,BFS。
  • (力扣)循环队列的实现与详解(C语言)
  • (牛客腾讯思维编程题)编码编码分组打印下标题目分析
  • (入门自用)--C++--抽象类--多态原理--虚表--1020
  • (十六)一篇文章学会Java的常用API
  • (一) 初入MySQL 【认识和部署】
  • (一)Neo4j下载安装以及初次使用