C++exceptionprocessingtutorial

LearningC++in exceptionprocessingmechanism, includingexception 抛出, 捕获 and processing

返回tutoriallist

1. exceptionprocessingoverview

1.1 what is exception?

exception is 程序run过程in发生 特殊circumstances, such as除以零, array越界, memory不足etc.. 这些circumstances可能导致程序崩溃 or 产生error结果.

in C++in, exceptionprocessingproviding了一种mechanism, 使得程序able to优雅地processing这些exceptioncircumstances, 而不 is 直接崩溃.

1.2 exceptionprocessing 优势

  • 分离errorprocessingcode: 将errorprocessingcode and 正常业务逻辑分离, improvingcode readable 性 and 可maintenance性.
  • 传递errorinformation: 可以将errorinformation from 发生error 地方传递 to able toprocessing该error 地方.
  • 统一errorprocessing: providing了一种统一 errorprocessingmechanism, 适用于不同class型 error.
  • resourcemanagement: 结合RAII (resource获取即初始化) mechanism, 可以确保resource in exception发生时正确释放.

2. exceptionprocessing basic语法

2.1 抛出exception

usingthrow关键字抛出exception:

throw exception值;

exception值可以 is 任何class型, includingbasicclass型, classobjectetc..

2.2 捕获exception

usingtry-catch语句捕获exception:

try {
    // 可能抛出exception code
} catch (exceptionclass型1 exceptionvariable) {
    // processingexceptionclass型1 code
} catch (exceptionclass型2 exceptionvariable) {
    // processingexceptionclass型2 code
} catch (...) {
    // processingotherclass型exception code
}

2.3 exceptionprocessingexample

#include <iostream>
#include <string>

using namespace std;

int divide(int a, int b) {
    if (b == 0) {
        throw string("除数不能 for 零");
    }
    return a / b;
}

int main() {
    try {
        int result = divide(10, 0);
        cout << "结果: " << result << endl;
    } catch (string e) {
        cout << "捕获 to exception: " << e << endl;
    } catch (...) {
        cout << "捕获 to 未知exception" << endl;
    }
    
    cout << "程序继续执行" << endl;
    return 0;
}

run结果:

捕获 to exception: 除数不能 for 零
程序继续执行

3. exception 传播

3.1 exception 栈unfold

当exception被抛出但 in 当 before functionin没 has 被捕获时, exception会沿着调用栈向 on 传播, 直 to 找 to able to捕获该exception catch块. 这个过程称 for 栈unfold (stack unwinding) .

in 栈unfold过程in, 会自动销毁 in exception发生点之 after creation 局部object.

3.2 exception传播example

#include <iostream>

using namespace std;

void func3() {
    cout << "进入func3" << endl;
    throw 100; // 抛出exception
    cout << "离开func3" << endl; // 不会执行
}

void func2() {
    cout << "进入func2" << endl;
    func3();
    cout << "离开func2" << endl; // 不会执行
}

void func1() {
    cout << "进入func1" << endl;
    func2();
    cout << "离开func1" << endl; // 不会执行
}

int main() {
    cout << "进入main" << endl;
    
    try {
        func1();
    } catch (int e) {
        cout << "捕获 to exception: " << e << endl;
    }
    
    cout << "离开main" << endl;
    return 0;
}

run结果:

进入main
进入func1
进入func2
进入func3
捕获 to exception: 100
离开main

4. exception层次structure

4.1 标准exceptionclass

C++标准libraryproviding了一系列exceptionclass, 它们都inheritance自基classexception. 这些exceptionclass定义 in 头file<stdexcept>in.

4.1.1 common 标准exceptionclass

  • std::exception: 所 has 标准exception 基class
  • std::bad_alloc: memory分配失败时抛出
  • std::bad_cast: class型转换失败时抛出
  • std::bad_typeid: usingtypeidoperation符时抛出
  • std::logic_error: 逻辑error, such asparameter无效
  • std::runtime_error: run时error, such as除以零

4.2 自定义exceptionclass

可以throughinheritanceexceptionclass or 其forkclass来creation自定义exceptionclass:

#include <iostream>
#include <exception>
#include <string>

using namespace std;

class MyException : public exception {
private:
    string message;
public:
    MyException(const string& msg) : message(msg) {}
    
    const char* what() const noexcept override {
        return message.c_str();
    }
};

void func() {
    throw MyException("自定义exception");
}

int main() {
    try {
        func();
    } catch (const exception& e) {
        cout << "捕获 to exception: " << e.what() << endl;
    }
    
    return 0;
}

5. exceptionsecurity

5.1 exceptionsecurity concepts

exceptionsecurity is 指程序 in 发生exception时, able to保持object处于 has 效status, will not causeresource泄漏 or data损 bad .

5.2 exceptionsecurity级别

  • 无抛出保证 (nothrow guarantee) : function承诺不会抛出任何exception.
  • 强exceptionsecurity保证 (strong exception safety guarantee) : such as果function抛出exception, 程序status不会改变, 相当于function from 未被调用过.
  • basicexceptionsecurity保证 (basic exception safety guarantee) : such as果function抛出exception, 程序status仍然 has 效, 但可能 and 调用 before 不同.
  • 无exceptionsecurity保证: function抛出exception时, 程序可能处于无效status.

5.3 RAII and exceptionsecurity

RAII (Resource Acquisition Is Initialization, resource获取即初始化) is aC++programmingtechniques, 它将resource 获取 and object 初始化绑定, 将resource 释放 and object 销毁绑定.

RAII可以确保即使 in exception发生时, resource也能被正确释放:

#include <iostream>
#include <memory>

using namespace std;

class Resource {
public:
    Resource() {
        cout << "获取resource" << endl;
    }
    
    ~Resource() {
        cout << "释放resource" << endl;
    }
    
    void use() {
        cout << "usingresource" << endl;
        throw runtime_error("usingresource时发生error");
    }
};

int main() {
    try {
        // using智能指针managementresource
        unique_ptr res(new Resource());
        res->use();
    } catch (const exception& e) {
        cout << "捕获 to exception: " << e.what() << endl;
    }
    
    // 即使发生exception, resource也会被正确释放
    cout << "程序继续执行" << endl;
    return 0;
}

6. exceptionprocessing best practices

6.1 whenusingexception

  • 用于processing程序无法正常继续执行 严重error.
  • 用于processing不common但可能发生 errorcircumstances.
  • 用于跨 many 个function层次传递errorinformation.

6.2 when不usingexception

  • 用于processing程序可以正常processing 预期circumstances.
  • in performance关键 codein, 因 for exceptionprocessing会带来一定 performance开销.
  • in 底层systemcodein, such asoperationsystem in 核.

6.3 exceptionprocessing best practices

  • using具体 exceptionclass型: 尽量using具体 exceptionclass型, 而不 is common exception.
  • 捕获适当 exception: 只捕获你able toprocessing exception.
  • usingRAIImanagementresource: 确保resource in exception发生时able to被正确释放.
  • 不要 in 析构functionin抛出exception: 析构function应该 is noexcept , 否则可能导致程序终止.
  • providing has 意义 exceptioninformation: in exceptioninpackage含足够 information, 以便于debug.
  • usingexception规范 (C++11 before ) or noexcept (C++11及以 after ) : 明确function exceptionbehavior.

实践case: 银行account余额management

writing一个C++程序, implementation银行account 余额management, including存款, 取款functions, 并usingexceptionprocessing来processing余额不足 circumstances.

requirementsanalysis

  • creation一个BankAccountclass, package含账号, 余额etc.property.
  • implementationdepositmethod用于存款.
  • implementationwithdrawmethod用于取款, 当余额不足时抛出exception.
  • implementationexceptionprocessing, 捕获并processing余额不足 exception.

referencecode

#include <iostream>
#include <string>
#include <exception>

using namespace std;

class InsufficientFundsException : public exception {
private:
    string message;
public:
    InsufficientFundsException(double balance, double amount) {
        message = "余额不足: 当 before 余额 " + to_string(balance) + ", 尝试取款 " + to_string(amount);
    }
    
    const char* what() const noexcept override {
        return message.c_str();
    }
};

class BankAccount {
private:
    string accountNumber;
    double balance;
public:
    BankAccount(const string& accNum, double initialBalance) : 
        accountNumber(accNum), balance(initialBalance) {}
    
    void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            cout << "存款成功: " << amount << ", 当 before 余额: " << balance << endl;
        }
    }
    
    void withdraw(double amount) {
        if (amount > balance) {
            throw InsufficientFundsException(balance, amount);
        }
        balance -= amount;
        cout << "取款成功: " << amount << ", 当 before 余额: " << balance << endl;
    }
    
    double getBalance() const {
        return balance;
    }
    
    string getAccountNumber() const {
        return accountNumber;
    }
};

int main() {
    try {
        BankAccount acc("123456", 1000.0);
        
        acc.deposit(500.0);
        acc.withdraw(800.0);
        acc.withdraw(1000.0); // 这会抛出exception
    } catch (const InsufficientFundsException& e) {
        cout << "捕获 to exception: " << e.what() << endl;
    } catch (const exception& e) {
        cout << "捕获 to otherexception: " << e.what() << endl;
    }
    
    cout << "程序继续执行" << endl;
    return 0;
}

run结果

存款成功: 500, 当 before 余额: 1500
取款成功: 800, 当 before 余额: 700
捕获 to exception: 余额不足: 当 before 余额 700, 尝试取款 1000
程序继续执行

互动练习

练习1: writing一个C++function, 计算两个整数 除法, 当除数 for 零时抛出exception. in mainfunctionin捕获并processing这个exception.

练习2: creation一个自定义exceptionclassNegativeNumberException, 当尝试计算负数 平方根时抛出此exception.

练习3: modify实践casein BankAccountclass, 添加转账functions, 并processing可能 exceptioncircumstances.