使用带自定义删除器的unique_ptr处理数组时遇编译错误求解决
问题描述
我正在使用自带内存管理机制的C框架(DPDK),想用std::unique_ptr封装这类特殊指针,需要自定义删除器来调用框架的释放函数rte_free,同时还要实现类似std::make_unique的工厂函数。
非数组类型的版本已经实现成功,但数组类型的代码编译报错。
现有代码
template<typename T> struct HugepageDeleter { void operator()(T* b) { rte_free(b); } }; template< typename T > using unique_hugepage = std::unique_ptr<T, HugepageDeleter<T>>; /// std::make_unique for single objects template<typename T, typename... Args> unique_hugepage<T> make_unique_hugepage(Args&&... args) { void *ptr = rte_malloc(nullptr, sizeof(T), alignof(T)); auto t = new (ptr) T(std::forward<Args>(args)...); return unique_hugepage<T>(t); } template<typename T> unique_hugepage<T> make_unique_hugepage_array(size_t num) { void *ptr = rte_malloc(nullptr, sizeof(std::remove_extent_t<T>[num]), alignof(T)); return unique_hugepage<std::remove_extent_t<T>[]>((std::remove_extent_t<T> *)ptr); } int test() { unique_hugepage<int> p = make_unique_hugepage<int>(); auto testData = make_unique_hugepage_array<unsigned char[]>(16000); }
编译错误信息
/usr/include/c++/10/bits/unique_ptr.h:612:17: error: no match for call to ‘(std::unique_ptr<unsigned char [], HugepageDeleter<unsigned char []> >::deleter_type {aka HugepageDeleter<unsigned char []>}) (unsigned char*&)’ 612 | get_deleter()(__ptr); | ~~~~~~~~~~~~~^~~~~~~ /.../HugepageMemory.h:14:10: note: candidate: ‘void HugepageDeleter<T>::operator()(T*) [with T = unsigned char []]’ 14 | void operator()(T* b) { rte_free(b); } | ^~~~~~~~ /.../HugepageMemory.h:14:24: note: no known conversion for argument 1 from ‘unsigned char*’ to ‘unsigned char (*)[]’ 14 | void operator()(T* b) { rte_free(b); } | ~~~^
问题原因与解决方法
问题根源
当T是数组类型(比如unsigned char[])时,HugepageDeleter<T>::operator()的参数类型是T*,也就是unsigned char (*)[](指向数组的指针),但std::unique_ptr<T[]>持有的是unsigned char*(指向数组元素的指针),两者类型不兼容,导致删除器调用时无法匹配。
解决步骤
- 特化数组类型的删除器:为数组类型单独实现删除器,让其接受元素指针而非数组指针。
- 调整工厂函数的类型推导:确保数组版本的工厂函数返回正确的
unique_hugepage类型,避免类型不匹配。
修正后的代码如下:
#include <memory> #include <type_traits> // 基础删除器,处理非数组类型 template<typename T> struct HugepageDeleter { void operator()(T* b) noexcept { rte_free(b); } }; // 特化数组类型的删除器 template<typename T> struct HugepageDeleter<T[]> { void operator()(T* b) noexcept { rte_free(b); } }; // 特化带大小的数组类型(可选,兼容形如T[N]的类型) template<typename T, size_t N> struct HugepageDeleter<T[N]> { void operator()(T* b) noexcept { rte_free(b); } }; template<typename T> using unique_hugepage = std::unique_ptr<T, HugepageDeleter<T>>; // 非数组版本的工厂函数 template<typename T, typename... Args> unique_hugepage<T> make_unique_hugepage(Args&&... args) { void* ptr = rte_malloc(nullptr, sizeof(T), alignof(T)); auto t = new (ptr) T(std::forward<Args>(args)...); return unique_hugepage<T>(t); } // 数组版本的工厂函数,推导元素类型 template<typename T> unique_hugepage<T[]> make_unique_hugepage_array(size_t num) { using ElementType = std::remove_extent_t<T>; void* ptr = rte_malloc(nullptr, sizeof(ElementType) * num, alignof(ElementType)); return unique_hugepage<ElementType[]>(static_cast<ElementType*>(ptr)); } int test() { unique_hugepage<int> p = make_unique_hugepage<int>(); // 两种调用方式都支持 auto testData1 = make_unique_hugepage_array<unsigned char>(16000); auto testData2 = make_unique_hugepage_array<unsigned char[]>(16000); }
关键说明
- 对数组类型的删除器进行特化后,
HugepageDeleter<T[]>::operator()接受的参数是T*,和std::unique_ptr<T[]>持有的指针类型完全匹配,解决了类型转换问题。 - 数组工厂函数支持两种调用方式:直接传元素类型(如
unsigned char)或数组类型(如unsigned char[]),std::remove_extent_t会自动处理类型推导,保持调用灵活性。 - 删除器标记为
noexcept,符合标准库对删除器的 noexcept 要求,同时避免不必要的异常开销。
内容的提问来源于stack exchange,提问作者Maximilian Engelhardt
相关产品推荐
相关产品推荐

