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