C++ 面试题 目录

C++ 中如何编写异常安全的代码?

推荐答案

在C++中编写异常安全的代码,通常遵循以下几个原则:

  1. 资源管理:使用RAII(Resource Acquisition Is Initialization)模式,确保资源在对象生命周期结束时自动释放。例如,使用智能指针(如std::unique_ptrstd::shared_ptr)来管理动态内存。

  2. 异常安全保证:确保代码在抛出异常时不会泄漏资源或破坏数据。常见的异常安全保证有三种:

    • 基本保证:程序在抛出异常后保持有效状态,不会泄漏资源。
    • 强保证:操作要么完全成功,要么完全失败,不会产生部分修改。
    • 不抛出保证:操作保证不会抛出异常。
  3. 避免裸指针:尽量避免使用裸指针,使用智能指针或其他资源管理类来管理资源。

  4. 异常处理:在适当的地方捕获异常,并确保资源在异常处理过程中得到正确释放。

  5. 事务性操作:对于需要多个步骤的操作,使用事务性操作来确保操作的原子性。如果某个步骤失败,可以回滚之前的操作。

本题详细解读

1. RAII模式

RAII是C++中管理资源的核心思想。通过将资源绑定到对象的生命周期,确保资源在对象销毁时自动释放。例如:

-- -------------------- ---- -------
----- ----------- -
-------
    ----------------- ------------ --------- - ---------------------------------- ----- -
        -- -------- -
            ----- -------------------------- -- ---- -------
        -
    -

    -------------- -
        -- ------- -
            -------------------
        -
    -

    -- ---------
    ----------------- ------------- - -------
    ------------ --------------- ------------- - -------

--------
    ---------- ------
--

在这个例子中,FileHandler类负责管理文件句柄。当FileHandler对象销毁时,文件句柄会自动关闭,即使在构造函数中抛出异常,也不会发生资源泄漏。

2. 异常安全保证

基本保证

基本保证要求程序在抛出异常后保持有效状态,不会泄漏资源。例如:

在这个例子中,即使processFile函数中抛出异常,FileHandler的析构函数也会确保文件被正确关闭。

强保证

强保证要求操作要么完全成功,要么完全失败,不会产生部分修改。例如:

为了提供强保证,可以使用“复制-交换”惯用法:

-- -------------------- ---- -------
---- ---------------------- ----- -------- --- ------ ------- -
    ------- -------- - -----
    ------- ------ - ---

    --------------------------
    -----------------------

    -- -----------
    ---- - ---------
    -- - -------
-

在这个例子中,只有在所有操作都成功的情况下,才会修改原始数据。

不抛出保证

不抛出保证要求操作不会抛出异常。例如:

3. 避免裸指针

使用智能指针可以避免手动管理内存,减少资源泄漏的风险。例如:

4. 异常处理

在适当的地方捕获异常,并确保资源在异常处理过程中得到正确释放。例如:

5. 事务性操作

对于需要多个步骤的操作,使用事务性操作来确保操作的原子性。例如:

-- -------------------- ---- -------
---- ------------------------ -
    --- -
        -- ---
        -- ---
        -- ---
    - ----- ----- -
        -- ----
        ------
    -
-

在这个例子中,如果任何一个步骤失败,可以回滚之前的操作,确保数据的一致性。

纠错
反馈