C++异常处理完全指南:从原理到实战

文章目录

异常的基本概念

异常是程序运行时发生的非预期事件(如除零、内存不足)。C++通过try、catch和throw提供结构化处理机制,使程序能够优雅处理错误,而非直接崩溃。

核心思想:将错误处理与正常逻辑分离,提高代码可读性和健壮性。

基本异常抛出与捕获

场景:处理除零错误,抛出并捕获异常。

cpp 复制代码
#include <iostream>
#include <stdexcept>  // 标准异常头文件

double divide(double a, double b) 
{
    if (b == 0) 
    {
        throw std::runtime_error("Error: Division by zero!");
    }
    return a / b;
}

int main() 
{
    try 
    {
        double result = divide(10, 0);
        std::cout << "Result: " << result << std::endl;
    } 
    catch (const std::runtime_error& e) 
    {
        std::cout << "Caught exception: " << e.what() << std::endl;
    }
    return 0;
}
输出:
Caught exception: Error: Division by zero!

说明:

  • throw 抛出一个 std::runtime_error 异常对象。
  • try 块内调用可能抛出异常的代码。
  • catch 捕获特定异常,e.what() 返回错误信息

多类型异常捕获

场景:根据错误类型抛出不同异常,并分别处理。

cpp 复制代码
#include <iostream>
#include <stdexcept>

void processInput(int value) 
{
    if (value < 0) 
    {
        throw std::invalid_argument("Negative value not allowed!");
    } 
    else if (value > 100) 
    {
        throw std::out_of_range("Value exceeds limit!");
    }
    // 其他逻辑
}

int main() 
{
    try 
    {
        processInput(-5);  // 触发invalid_argument
    } catch (const std::invalid_argument& e) 
    {
        std::cout << "Invalid Argument: " << e.what() << std::endl;
    } catch (const std::out_of_range& e) 
    {
        std::cout << "Out of Range: " << e.what() << std::endl;
    } catch (...) 
    {
        std::cout << "Unknown error!" << std::endl;
    }
    return 0;
}
输出:
Invalid Argument: Negative value not allowed!

说明:

  • 多个 catch 块按顺序匹配异常类型。
  • catch (...) 捕获所有未被匹配的异常。

异常重新抛出

场景:中间层捕获异常后记录日志,重新抛出供上层处理。

cpp 复制代码
#include <iostream>
#include <stdexcept>

void lowLevel() 
{
    throw std::runtime_error("Low-level failure!");
}

void highLevel() 
{
    try 
    {
        lowLevel();
    } catch (const std::runtime_error& e) 
    {
        std::cout << "Logged: " << e.what() << std::endl;
        throw;  // 重新抛出当前异常
    }
}

int main() 
{
    try 
    {
        highLevel();
    } 
    catch (const std::runtime_error& e) 
    {
        std::cout << "Main caught: " << e.what() << std::endl;
    }
    return 0;
}
输出:
Logged: Low-level failure!
Main caught: Low-level failure!

异常安全

核心原则

  • 基本保证:异常发生后,程序处于有效状态(无资源泄漏)。
  • 强保证:操作要么成功,要么状态回滚到操作前(类似事务)。
  • 无抛出保证:操作绝不抛出异常(如swap)。

场景:使用智能指针确保资源在异常发生时自动释放。

cpp 复制代码
#include <iostream>
#include <memory>
#include <stdexcept>

class Resource 
{
public:
    Resource() { std::cout << "Resource acquired.\n"; }
    ~Resource() { std::cout << "Resource released.\n"; }
};

void riskyOperation() 
{
    auto res = std::make_unique<Resource>();  // RAII管理
    throw std::runtime_error("Oops, something broke!");
    // 即使抛出异常,res的析构函数也会被调用
}

int main() 
{
    try 
    {
        riskyOperation();
    } 
    catch (const std::runtime_error& e) 
    {
        std::cout << "Error: " << e.what() << std::endl;
    }
    return 0;
}
输出:
Resource acquired.
Resource released.
Error: Oops, something broke!

说明:

  • RAII(资源获取即初始化)通过对象生命周期管理资源。
  • 智能指针(如 std::unique_ptr)确保内存自动释放。

异常规范(noexcept)

场景:标记不抛出异常的函数。

cpp 复制代码
#include <iostream>
#include <stdexcept>

void safeSwap(int& a, int& b) noexcept 
{  // 保证不抛出异常
    int temp = a;
    a = b;
    b = temp;
}

int main() 
{
    int x = 10, y = 20;
    safeSwap(x, y);
    std::cout << "x=" << x << ", y=" << y << std::endl;
    return 0;
}
输出:
x=20, y=10

栈展开与析构

场景:异常抛出时,栈展开触发局部对象析构。

cpp 复制代码
#include <iostream>
#include <stdexcept>

class Logger 
{
public:
    Logger() { std::cout << "Logger created.\n"; }
    ~Logger() { std::cout << "Logger destroyed.\n"; }
};

void functionB() 
{
    Logger log;  // 局部对象
    throw std::runtime_error("Error in functionB");
}

void functionA() 
{
    try 
    {
        functionB();
    } 
    catch (...) 
    {
        std::cout << "Caught in functionA\n";
        throw;
    }
}

int main() 
{
    try 
    {
        functionA();
    } 
    catch (...) 
    {
        std::cout << "Caught in main\n";
    }
    return 0;
}
输出:
Logger created.
Logger destroyed.
Caught in functionA
Caught in main

说明:

栈展开时,log 的析构函数被调用。

标准库异常

C++标准库也定义了⼀套⾃⼰的⼀套异常继承体系库,基类是exception,所以我们⽇常写程序,需要在主函数捕获exception即可,要获取异常信息,调⽤what函数,what是⼀个虚函数,派⽣类可以重写。

总结

通过这些例子,你可以看到 C++ 异常处理的不同应用场景,包括:

  • 如何通过 throw 抛出异常,并通过 catch 捕获处理。
  • 通过多个 catch 语句来处理不同类型的异常。
  • 异常的重新抛出以及其应用。
  • 异常安全,如何通过智能指针避免资源泄漏。
  • 如何使用标准库中的异常类来捕获和处理常见的错误。

这些例子展示了 C++ 异常处理机制在实际编程中的强大作用,可以帮助程序员有效地管理和应对程序运行中的错误。

相关推荐
库玛西1 小时前
深入浅出传输层:UDP 与 TCP 协议全景指南
linux·服务器·网络·c++·笔记·tcp/ip·udp
Chester_19997 小时前
CSP202203C.计算资源调度器
开发语言·数据结构·c++·蓝桥杯
会周易的程序员9 小时前
给 PLC 写一个字节码虚拟机:STVM 虚拟机架构设计
开发语言·c++·虚拟机·软plc·iec61131·stvm
小灰灰搞电子9 小时前
完全驾驭 Qt 与数据库:C++ ORM 框架 QxOrm 原理与实践指南
数据库·c++·qt
QT界面美化性能优化9 小时前
QT+AI:使用AI技术为QT应用程序赋能
c++·人工智能·qt·opencv·qt教程·qt6.3
是隼人9 小时前
buuctf-pwn xdctf2015_pwn200题解(学习过程持续更新)
c语言·学习·安全·pwn入门·ctf入门
学习星球11 小时前
单调栈——从“找下一个更大的“到柱状图中的最大矩形
数据库·c++·算法·leetcode·xcode
小灰灰搞电子12 小时前
C++ 引用折叠详解
c++
布莱克60513 小时前
数组详解:定义、作用、应用场景及与链表的区别(C/C++ 代码讲解)
c语言·开发语言·c++·数组
hongmai66688813 小时前
MP2348GTL-Z:这颗24V/4A同步降压芯片,把性能和体积平衡得恰到好处
c语言·开发语言·arm开发·单片机·5g