1. 当异常遇上裸指针:C++内存泄漏的经典陷阱
我刚入行C++开发时,曾经写过这样一个函数:
cpp复制void processFile(const char* filename) {
FILE* file = fopen(filename, "r");
if (!file) {
throw std::runtime_error("文件打开失败");
}
char* buffer = new char[1024];
// 处理文件内容...
fclose(file);
delete[] buffer;
}
看起来逻辑很完美是吧?打开文件、分配内存、处理数据、最后释放资源。但这里隐藏着一个致命问题——当文件处理过程中抛出异常时,delete[] buffer这行代码根本不会执行!
这就是C++异常处理中最经典的陷阱:异常会导致代码执行路径突然跳转,使得手动管理的内存资源无法被正确释放。在我的职业生涯中,见过太多因为这种问题导致的内存泄漏,特别是在长期运行的服务程序中,这种泄漏会逐渐累积最终引发系统崩溃。
关键教训:任何在new和delete之间可能抛出异常的地方,都是内存泄漏的高危区
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 智能指针如何成为异常安全的关键
2.1 RAII:C++资源管理的基石
智能指针的核心思想是RAII(Resource Acquisition Is Initialization),这是Bjarne Stroustrup提出的C++核心设计理念。其本质是:
- 将资源获取与对象生命周期绑定
- 利用栈对象析构函数自动释放资源
- 确保异常发生时资源仍能被正确释放
让我们用std::unique_ptr重写之前的危险代码:
cpp复制void safeProcessFile(const std::string& filename) {
std::unique_ptr<FILE, decltype(&fclose)> file(fopen(filename.c_str(), "r"), &fclose);
if (!file) {
throw std::runtime_error("文件打开失败");
}
std::unique_ptr<char[]> buffer(new char[1024]);
// 处理文件内容...
// 即使这里抛出异常,buffer和file也会被自动释放
}
2.2 三种智能指针的异常安全特性对比
| 智能指针类型 | 所有权语义 | 异常安全性 | 典型使用场景 |
|---|---|---|---|
| unique_ptr | 独占所有权 | 最高 | 局部变量、工厂函数返回值 |
| shared_ptr | 共享所有权 | 高 | 需要共享的长期存活对象 |
| weak_ptr | 观察指针 | 不适用 |
