如何用智能指针修复遗留API中的内存泄漏问题?
方案1:极简自定义RAII守卫(最推荐)
直接用内嵌的轻量结构体实现RAII,语义清晰且代码极简,完美适配场景:
void* badGetVector() { const int len = 4; void *y = nullptr; // 内嵌RAII守卫:作用域结束时自动释放y指向的内存 struct ScopeFreeGuard { void*& target; explicit ScopeFreeGuard(void*& ptr) : target(ptr) {} ~ScopeFreeGuard() { if (target) free(target); } // 禁止拷贝,避免意外行为 ScopeFreeGuard(const ScopeFreeGuard&) = delete; ScopeFreeGuard& operator=(const ScopeFreeGuard&) = delete; } guard(y); // 此处的样板代码、分支逻辑、提前返回都能被正确处理: // 任何提前返回都会触发guard析构,自动释放已分配的y ultraLegacyApi(&y); return new std::vector<int>((int*)y, (int*)y + len); // 函数结束时guard自动析构,free(y),vector已复制数据,安全无泄漏 }
这个方案的优势:
- 语义明确:结构体名字直接表明用途,可读性拉满
- 零额外依赖:纯标准C++实现,不依赖STL智能指针的“滥用”
- 覆盖全分支:不管是正常返回还是提前跳出,都能保证内存释放
- 代码紧凑:内嵌在函数内部,不污染全局命名空间
方案2:STL智能指针包装实现(标准库风格)
如果更倾向于用STL组件,可以用unique_ptr托管一个自定义包装结构体,借助智能指针的自动析构特性:
#include <memory> void* badGetVector() { const int len = 4; // 用unique_ptr管理包装结构体,自动调用析构释放内存 auto ptrWrapper = std::make_unique<struct { void* data = nullptr; ~decltype(auto)() { if (data) free(data); } }>(); ultraLegacyApi(&ptrWrapper->data); return new std::vector<int>((int*)ptrWrapper->data, (int*)ptrWrapper->data + len); }
关于原有方案的说明
- 你用
shared_ptr模拟作用域守卫的思路是正确的,但shared_ptr的核心语义是共享所有权,和当前场景需要的独占式作用域清理语义不匹配,属于“用错工具”,所以显得不够优雅。 - 直接用
unique_ptr失败的原因是:get()返回的是内部指针的副本,无法获取其原始地址传给ultraLegacyApi修改,而上面的方案通过引用捕获或包装类解决了这个问题。
内容的提问来源于stack exchange,提问作者pptaszni
相关产品推荐
相关产品推荐

