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

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

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

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

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

2. 标准异常类std::exception

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

示例代码:

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

3. 运行时异常std::runtime_error

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

示例代码:

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

4. 逻辑异常std::logic_error

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

示例代码:

cpp 复制代码
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通常不是直接抛出的,而是当标准异常处理机制遇到问题时由编译器抛出。

示例代码:

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

5.2 std::bad_alloc

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

示例代码:

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

5.3 std::bad_cast

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

示例代码:

cpp 复制代码
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操作符通常不会失败。

示例代码:

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

5.5 std::domain_error

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

示例代码:

cpp 复制代码
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

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

示例代码:

cpp 复制代码
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

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

示例代码:

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

5.8 std::out_of_range

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

示例代码:

cpp 复制代码
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

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

示例代码:

cpp 复制代码
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

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

示例代码:

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

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

通用异常处理示例代码:

cpp 复制代码
#include <stdexcept>
#include <new> // For std::bad_alloc
#include <typeinfo> // For std::bad_cast

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

6. 自定义异常类

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

示例代码:

cpp 复制代码
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++异常处理机制的完整示例程序。这个程序演示了如何定义一个自定义异常类,抛出和捕获不同类型的异常,并展示了异常处理的最佳实践。

cpp 复制代码
#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++的异常处理机制来处理程序中的错误情况,包括自定义异常和标准库异常。通过这种方式,我们可以在不中断程序正常流程的情况下优雅地处理错误。


分享一个有趣的 学习链接

相关推荐
量子-Alex4 分钟前
【多模态聚类】用于无标记视频自监督学习的多模态聚类网络
学习·音视频·聚类
吉大一菜鸡9 分钟前
FPGA学习(基于小梅哥Xilinx FPGA)学习笔记
笔记·学习·fpga开发
CCSBRIDGE3 小时前
Magento2项目部署笔记
笔记
爱吃西瓜的小菜鸡3 小时前
【C语言】判断回文
c语言·学习·算法
别NULL3 小时前
机试题——疯长的草
数据结构·c++·算法
小A1593 小时前
STM32完全学习——SPI接口的FLASH(DMA模式)
stm32·嵌入式硬件·学习
亦枫Leonlew3 小时前
微积分复习笔记 Calculus Volume 2 - 5.1 Sequences
笔记·数学·微积分
岁岁岁平安4 小时前
spring学习(spring-DI(字符串或对象引用注入、集合注入)(XML配置))
java·学习·spring·依赖注入·集合注入·基本数据类型注入·引用数据类型注入
武昌库里写JAVA4 小时前
Java成长之路(一)--SpringBoot基础学习--SpringBoot代码测试
java·开发语言·spring boot·学习·课程设计
qq_589568104 小时前
数据可视化echarts学习笔记
学习·信息可视化·echarts