You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用带自定义删除器的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*(指向数组元素的指针),两者类型不兼容,导致删除器调用时无法匹配。

解决步骤

  1. 特化数组类型的删除器:为数组类型单独实现删除器,让其接受元素指针而非数组指针。
  2. 调整工厂函数的类型推导:确保数组版本的工厂函数返回正确的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 09:40:37