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

c++异常详解

概念介绍

异常是一种处理程序错误的机制。用于:

  • 将错误检测与错误处理分离
  • 确保资源正确释放
  • 允许错误处理代码集中处理

说到异常就离不开try/catch/noexcept/throw这个几个关键字。它们的作用如下:

  • try/catch:这两个关键字成对使用,只有用这两个关键字包含的代码抛出的错误才能被捕获。catach后的用于错误处理,try部分的代码用于错误检测。
  • throw:抛出异常的关键字。
  • noexcept:c++11引入的新的关键字,通过该关键字可以显式的告诉编译器某个函数是否可能抛出异常。

基本的使用方法如下:

// 基本语法
try {
    // 可能抛出异常的代码
    throw MyException("error message");
} catch (const MyException& e) {
    // 处理特定类型异常
} catch (...) {
    // 处理任何异常
}

头文件依赖:#include <stdexcept> 

异常的种类

c++允许抛出任意类型的异常,例如整型,字符串,枚举等,但是c++最推荐的还是抛出继承自std::exception的异常类对象。另外c++还存在一些标准的异常类,即c++已经封装好的异常类。

标准异常类

#include <stdexcept>
#include <string>

void function() {
    // 1.1 标准异常类
    throw std::runtime_error("Runtime error occurred");  //运行时错误
    throw std::invalid_argument("Invalid argument");  //无效参数
    throw std::out_of_range("Index out of range");   //超出访问范围
    throw std::logic_error("Logic error");  //逻辑错误
    
    // 1.2 bad_alloc(内存分配失败)
    throw std::bad_alloc();
    
    // 1.3 bad_cast(类型转换失败)
    throw std::bad_cast();
}

自定义异常类

// 2.1 基本自定义异常
class DatabaseException : public std::exception {
public:
    DatabaseException(const std::string& message) 
        : message_(message) {}
    
    const char* what() const noexcept override {
        return message_.c_str();
    }
private:
    std::string message_;
};

// 2.2 带错误代码的异常
class NetworkException : public std::exception {
public:
    NetworkException(int errorCode, const std::string& message)
        : errorCode_(errorCode), message_(message) {}
    
    const char* what() const noexcept override {
        return message_.c_str();
    }
    
    int getErrorCode() const { return errorCode_; }
    
private:
    int errorCode_;
    std::string message_;
};

void connectToDatabase() {
    throw DatabaseException("Failed to connect to database");
    throw NetworkException(404, "Server not found");
}

基本数据类型(不推荐)

void riskyFunction() {
    // 3.1 整数
    throw 42;                     // 不推荐
    
    // 3.2 字符串字面量
    throw "Error occurred";       // 不推荐
    
    // 3.3 字符串对象
    throw std::string("Error");   // 不推荐
    
    // 3.4 布尔值
    throw false;                  // 不推荐
}

// 捕获基本类型的异常
void catchBasicTypes() {
    try {
        riskyFunction();
    } catch (int e) {
        std::cout << "Caught integer: " << e << std::endl;
    } catch (const char* e) {
        std::cout << "Caught string literal: " << e << std::endl;
    } catch (const std::string& e) {
        std::cout << "Caught string object: " << e << std::endl;
    }
}

枚举类型(某些场景下可以实现)

// 4.1 普通枚举
enum ErrorCode {
    FILE_NOT_FOUND,
    PERMISSION_DENIED,
    NETWORK_ERROR
};

// 4.2 枚举类
enum class Status {
    Success,
    Failed,
    Timeout
};

void processFile() {
    throw ErrorCode::FILE_NOT_FOUND;    // 可以,但不推荐
    throw Status::Failed;               // 可以,但不推荐
}

// 捕获枚举异常
void catchEnums() {
    try {
        processFile();
    } catch (ErrorCode e) {
        switch(e) {
            case FILE_NOT_FOUND:
                std::cout << "File not found" << std::endl;
                break;
            case PERMISSION_DENIED:
                std::cout << "Permission denied" << std::endl;
                break;
        }
    } catch (Status s) {
        if (s == Status::Failed) {
            std::cout << "Operation failed" << std::endl;
        }
    }
}

注意事项

异常的处理是通过编译器在来实现的,通过编译器在对应的位置插入代码,其功能与return有些类似,遇到异常后,后续的代码均不会执行,但是会释放函数内部的局部变量。请看下面的例子:

class Resource {
public:
    Resource() { cout << "Resource constructed\n"; }
    ~Resource() { cout << "Resource destroyed\n"; }
};

void f3() {
    cout << "f3 start\n";
    throw std::runtime_error("error in f3");  // 抛出异常
    cout << "f3 end\n";  // 永远不会执行
}

void f2() {
    cout << "f2 start\n";
    Resource r;          // 局部对象会被正确析构
    f3();               // 调用抛出异常的函数
    cout << "f2 end\n"; // 永远不会执行
}

void f1() {
    cout << "f1 start\n";
    f2();               // 调用最终抛出异常的函数
    cout << "f1 end\n"; // 永远不会执行
}

int main() {
    try {
        cout << "main start\n";
        f1();
        cout << "main end\n"; // 永远不会执行
    } catch (const std::exception& e) {
        cout << "Exception caught: " << e.what() << "\n";
    }
}

执行结果如下:

main start
f1 start
f2 start
Resource constructed
f3 start
Resource destroyed
Exception caught: error in f3

使用建议

  1.  优先使用标准异常类
  2. 如果需要自定义异常类,需要继承std::exception
  3. 避免使用基本类型作为异常

http://www.kler.cn/a/516388.html

相关文章:

  • WIN11 UEFI漏洞被发现, 可以绕过安全启动机制
  • 计算机视觉算法实战——无人机检测
  • K8S中Service详解(一)
  • doris:腾讯云 COS导入数据
  • iOS 权限管理:同时请求相机和麦克风权限的最佳实践
  • 3.CSS的背景
  • 【漫话机器学习系列】057.误报率(Flase Positive Rate, FPR)
  • python--列表list切分(超详细)
  • 【程序人生】瞰谷
  • 【设计模式-行为型】策略模式
  • 照片永久删除后的数据恢复全攻略
  • 100%全国产化时钟服务器、全国产化校时服务器、全国产化授时服务器
  • Docker Desktop 在Windows 环境中开发、测试和运行容器化的应用程序
  • JVM面试题解,垃圾回收之“垃圾回收器”剖析
  • pytest自动化测试 - pytest夹具的基本概念
  • 安全开发 JavaEE 反射机制 对象 成员变量 构造方法 成员方法 攻击链
  • HarmonyOS手势处理
  • 常见的备份服务器操作系统如何选择
  • 2025年数学建模美赛:A题分析(1)Testing Time: The Constant Wear On Stairs
  • C语言-运算符
  • 智慧冷库可视化监控系统
  • 服务器内部是如何运行的
  • 基于微信小程序的童装商城的设计与实现(LW+源码+讲解)
  • qml FileDialog 详解
  • 汇编与逆向(二)-汇编基础
  • 多管齐下以IP地址查询精度