std::unique_ptr使用函数作为删除器时出现默认构造不匹配错误
用普通函数作为std::unique_ptr删除器的编译错误原因及解决方法
问题场景
尝试将自定义普通函数作为std::unique_ptr的删除器时出现编译错误,但之前使用C函数作为删除器能正常工作,需明确问题根源。
示例代码
#include <cstdio> #include <memory> #include <utility> using cTYPE = struct { int a; }; void delete_wrapper(cTYPE* ptr) { return free(ptr); } cTYPE* new_wrapper() { return static_cast<cTYPE*>(malloc(sizeof(cTYPE))); } int main() { auto foo = []() { using tmp_storage_type = std::unique_ptr<cTYPE, decltype(delete_wrapper)>; static tmp_storage_type obj; obj = tmp_storage_type{ new_wrapper(), delete_wrapper }; }; foo(); }
编译报错信息
<source>:23:33: note: in instantiation of template class 'std::unique_ptr<cTYPE, void (cTYPE *)>' requested here static tmp_storage_type obj; ^ <source>:24:15: error: no matching constructor for initialization of 'tmp_storage_type' (aka 'unique_ptr<cTYPE, void (cTYPE *)>') obj = tmp_storage_type{ new_wrapper(), delete_wrapper };
根本原因
核心问题在于decltype(delete_wrapper)推导出来的是函数类型void(cTYPE*),而非函数指针类型void(*)(cTYPE*)。
当std::unique_ptr的删除器模板参数为函数类型时:
- 该模板特化会将删除器存储为函数指针,但函数类型无法默认构造,因此代码中
static tmp_storage_type obj;这行尝试默认构造unique_ptr对象时,编译器无法生成合法的默认构造函数。 - 后续赋值语句中,尝试用
new_wrapper()返回的指针和delete_wrapper函数值构造临时对象,此时因为删除器类型是函数类型,构造函数要求传递的删除器参数必须匹配函数类型的实例,但函数本身不能直接作为值传递,需隐式转换为指针,而这种情况下构造函数的参数匹配会失败,导致报错。
之前使用C函数能正常工作,大概率是因为当时显式使用了函数指针类型作为删除器,而非直接用函数类型。
解决方法
方法1:使用函数指针类型作为删除器
将删除器类型改为函数指针,可通过decltype(&delete_wrapper)直接推导,或显式写出指针类型:
// 方式1:用decltype获取函数指针类型 using tmp_storage_type = std::unique_ptr<cTYPE, decltype(&delete_wrapper)>; // 方式2:显式指定函数指针类型 using tmp_storage_type = std::unique_ptr<cTYPE, void(*)(cTYPE*)>;
修改后,默认构造的unique_ptr会将删除器指针初始化为空,后续赋值时传递delete_wrapper会隐式转换为函数指针,匹配构造函数参数。
方法2:使用Lambda作为删除器
Lambda的类型是匿名类类型,符合std::unique_ptr对删除器的要求(可构造、可调用),且无需手动处理指针类型:
auto foo = []() { using tmp_storage_type = std::unique_ptr<cTYPE, decltype([](cTYPE* ptr){ free(ptr); })>; static tmp_storage_type obj; obj = tmp_storage_type{ new_wrapper(), [](cTYPE* ptr){ free(ptr); } }; };
方法3:用std::function包装删除器(不推荐,有性能开销)
将删除器包装为std::function,牺牲一点性能换取类型灵活性:
using tmp_storage_type = std::unique_ptr<cTYPE, std::function<void(cTYPE*)>>; static tmp_storage_type obj; obj = tmp_storage_type{ new_wrapper(), delete_wrapper };
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

