C++ 基础:RAII、智能指针与项目构建
15.1 RAII
15.1.1 Exceptions(异常)
异常是处理代码中错误的一种方式。异常会被'抛出',我们可以通过编写代码来处理异常,从而继续执行而不一定出错。
在 C++ 代码中,可能存在多处抛出异常的路径。例如:
- Pet 的拷贝构造函数:函数参数采用值传递时可能抛出异常。
- 临时字符串构造:返回
std::string或进行拼接时可能因内存分配失败抛出异常。 - 成员函数调用:如
p.type()、p.firstName()等内部访问数据或分配内存时可能抛出异常。 - 运算符重载:字符串拼接运算符若用户自定义实现不当可能抛出异常。
- 返回字符串的拷贝构造:返回值拷贝时可能抛出异常。
这些潜在点提示了代码中存在多处引发异常的点,需要注意异常安全处理。
若使用裸指针管理资源(如 new Pet(petId)),存在严重漏洞:
- 若构造函数抛出异常,
delete p不会执行,导致内存泄漏。 - 若后续操作抛出异常,同样会跳过
delete p,导致内存泄漏。
15.1.2 资源获取即初始化 (RAII)
RAII(Resource Acquisition is Initialization)由 Bjarne Stroustrup 提出,核心是将资源管理与对象的生命周期强绑定。
原则:
- 类所使用的所有资源应在构造函数中获取。
- 类所使用的所有资源应在析构函数中释放。
本质:
- 资源获取(Acquisition = Initialization):在构造函数中完成资源申请(如
new、open()、lock())。确保对象创建成功即资源就绪。 - 资源释放(Release = Destruction):在析构函数中完成资源清理(如
delete、close()、unlock())。利用 C++ 自动调用析构函数的特性,随对象生命周期结束自动释放资源。
解决的核心问题:避免资源泄漏 手动管理资源易因逻辑漏洞(如忘记释放、提前 return、异常打断)导致泄漏。RAII 通过'自动析构'规避这些问题。
示例对比:
// 手动管理(风险高)
void badExample() {
int* ptr = new int[10]; // 手动获取资源
if (someCondition) {
return; // 提前返回,跳过 delete,内存泄漏!
}
[] ptr;
}
{
;
(someCondition) {
;
}
}


