MST

星途 面试题库

面试题:C++ 异常安全与模板元编程的结合

设计一个模板类 `SafeContainer`,它能够存储任意类型的对象,并提供异常安全的操作。要求在插入和删除元素时遵循异常安全的强保证,并且能够在编译期检测类型是否支持特定的异常安全语义。阐述你的设计理念并给出关键代码实现。
37.1万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

设计理念

  1. 存储任意类型对象:使用模板类 SafeContainer 来实现泛型存储,这样可以存储各种类型的对象。
  2. 异常安全的强保证
    • 插入操作:在插入新元素时,如果发生异常(例如内存分配失败),容器的状态不应改变,即不能有部分插入的情况。可以通过使用 std::vector 等容器作为底层存储,并在插入操作时利用其异常安全特性。如果插入操作抛出异常,std::vector 会自动回滚到插入前的状态。
    • 删除操作:删除元素时,如果发生异常(例如析构函数抛出异常,虽然不推荐但仍需考虑),容器应保持有效状态,并且不会丢失其他元素。同样利用 std::vector 的特性,删除元素后重新调整容器大小,若过程中出现异常,std::vector 会保证自身状态正确。
  3. 编译期检测类型是否支持特定异常安全语义:使用 SFINAE(Substitution Failure Is Not An Error)技术结合 std::is_nothrow_move_constructiblestd::is_nothrow_move_assignable 等类型 traits 来检测类型是否满足异常安全语义。例如,只有当类型是无异常移动构造和无异常移动赋值时,才允许该类型存储在容器中。

关键代码实现

#include <vector>
#include <type_traits>
#include <stdexcept>

template <typename T, typename = std::enable_if_t<
    std::is_nothrow_move_constructible<T>::value &&
    std::is_nothrow_move_assignable<T>::value
>>
class SafeContainer {
private:
    std::vector<T> data;

public:
    // 插入元素
    void insert(const T& value) {
        std::vector<T> temp = data;
        try {
            temp.push_back(value);
            data = std::move(temp);
        } catch (...) {
            // 如果插入失败,data 保持原来状态
            data = std::move(temp);
            throw;
        }
    }

    // 删除元素
    void remove(size_t index) {
        if (index >= data.size()) {
            throw std::out_of_range("Index out of range");
        }
        std::vector<T> temp = data;
        try {
            temp.erase(temp.begin() + index);
            data = std::move(temp);
        } catch (...) {
            // 如果删除失败,data 保持原来状态
            data = std::move(temp);
            throw;
        }
    }

    // 获取元素
    const T& get(size_t index) const {
        if (index >= data.size()) {
            throw std::out_of_range("Index out of range");
        }
        return data[index];
    }

    size_t size() const {
        return data.size();
    }
};