C++封装C遗留代码:为std::unique_ptr定义双参数自定义删除器
双参数自定义删除器实现方案
std::unique_ptr的自定义删除器签名仅支持接收1个入参,即智能指针当前托管的内存指针,你不需要让删除器本身支持双入参,只需要在初始化智能指针时,把数组长度作为状态绑定到删除器实例上即可,析构时删除器就能拿到长度参数调用遗留的双参释放接口。
方案1:Lambda表达式实现(最简洁,推荐)
利用Lambda的值捕获特性,把初始化时拿到的数组长度捕获到删除器内部,直接调用遗留释放逻辑即可:
#include <memory> #include <cstdlib> #include <cstdio> // 负责分配内存并返回缓冲区大小的函数 void legacyFunction(char **array, int *num) { char *p = (char *)calloc(5, sizeof(char)); for (auto i=0; i<5; ++i) { p[i] = 'a'; } *num = 5; *array = p; return; } // 示例:你现有的双参数遗留释放函数 void legacyArrayFree(char* ptr, int element_count) { printf("调用遗留释放逻辑,释放长度为%d的数组\n", element_count); free(ptr); } int main() { char *array = nullptr; int numofElts = 0; legacyFunction(&array, &numofElts); // 定义捕获了数组长度的删除器 auto deleter = [numofElts](char* ptr) { legacyArrayFree(ptr, numofElts); }; // 注意托管数组时模板参数要写char[],用decltype自动推导删除器类型 std::unique_ptr<char[], decltype(deleter)> managed_array(array, deleter); // 可以直接用[]下标访问元素,和普通数组用法一致 // managed_array[0] = 'b'; return 0; }
方案2:仿函数实现(兼容旧C++标准)
如果你的编译环境不支持C++11及以上的Lambda(极老的遗留项目场景),可以自定义仿函数结构体,把数组长度作为成员变量存储:
// 自定义删除器仿函数 struct LegacyArrayDeleter { int element_count; void operator()(char* ptr) const { legacyArrayFree(ptr, element_count); } }; int main() { char *array = nullptr; int numofElts = 0; legacyFunction(&array, &numofElts); // 初始化时传入绑定了长度的删除器实例 std::unique_ptr<char[], LegacyArrayDeleter> managed_array(array, LegacyArrayDeleter{numofElts}); return 0; }
注意事项
- 禁止尝试给删除器定义双入参接口:
std::unique_ptr析构时只会向删除器传入托管的指针,不会传入第二个长度参数,额外参数必须提前绑定为删除器的内部状态 - 托管
malloc/calloc分配的数组时,unique_ptr的第一个模板参数必须写为数组类型T[](示例中为char[]),不要写指针类型char*,避免语义错误 - 不推荐用
std::bind绑定参数实现删除器,写法可读性远低于Lambda和仿函数,后续维护成本高
内容的提问来源于stack exchange,提问作者Sanish
相关产品推荐
相关产品推荐

