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

C++中如何让不同删除器的std::unique_ptr兼容并存入指定数组

问题1 实现删除器兼容的方案

std::unique_ptr的删除器是其类型的组成部分,两种携带不同删除器类型的unique_ptr默认属于完全独立的类型,无法直接互相赋值。要实现需求有两种可行方案:

方案1:给目标删除器增加转换适配

首先修正删除器的定义(你当前的operator()缺少指针入参,不符合unique_ptr对删除器的要求),给deleter<ALLOC>增加empty_deleter的转换构造,同时增加空逻辑标识:

template<typename ALLOC>
class deleter {
public:
    // 支持从empty_deleter隐式转换
    template<typename T>
    deleter(const empty_deleter<T>&) noexcept : m_is_empty(true) {}
    // 原有默认构造,用于普通删除场景
    explicit deleter(ALLOC alloc = ALLOC()) noexcept : m_alloc(std::move(alloc)), m_is_empty(false) {}

    void operator()(T* ptr) const {
        if (m_is_empty) return;
        // 原有删除逻辑:先析构对象再释放内存
        std::allocator_traits<ALLOC>::destroy(m_alloc, ptr);
        m_alloc.deallocate(ptr, 1);
    }
private:
    ALLOC m_alloc;
    bool m_is_empty;
};

赋值时需要显式转移指针所有权,构造目标类型的unique_ptr:

std::unique_ptr<T, empty_deleter<T>> empty_ptr = /* 待存入的指针对象 */;
// 构造目标类型后存入数组
storage[i] = std::unique_ptr<T, deleter<std::allocator<T>>>(
    empty_ptr.release(), 
    empty_deleter<T>{}
);

方案2:用类型擦除统一删除器类型

将存储数组的删除器统一替换为类型擦除后的std::function<void(T*)>,不需要修改原有删除器的定义就可以兼容所有符合签名的删除器:

// 修改数组的元素定义
std::array<std::unique_ptr<T, std::function<void(T*)>>, 数组长度> storage;

// 存入带empty_deleter的指针
std::unique_ptr<T, empty_deleter<T>> empty_ptr = /* 待存入对象 */;
storage[i] = std::unique_ptr<T, std::function<void(T*)>>(
    empty_ptr.release(),
    empty_deleter<T>{}
);

// 普通带deleter的指针也可以直接存入
std::unique_ptr<T, deleter<std::allocator<T>>> normal_ptr = /* 普通指针对象 */;
storage[i] = std::unique_ptr<T, std::function<void(T*)>>(
    normal_ptr.release(),
    deleter<std::allocator<T>>{}
);

问题2 删除逻辑的调用规则

赋值完成后触发删除时,调用的是目标unique_ptr声明的删除器类型,也就是deleter<allocator<T>>的operator()。
原因是std::unique_ptr的删除器采用值语义存储:当你把携带empty_deleter的unique_ptr转换为目标类型时,会先以empty_deleter为入参构造一个deleter<allocator<T>>的实例,这个新的删除器实例会被存入目标unique_ptr,删除时只会调用该实例的operator(),原empty_deleter实例不会被保留。
如果你采用方案1的适配逻辑,目标删除器会根据m_is_empty标识走空分支,符合预期;如果没有做适配直接强制转换,会直接执行deleter<allocator<T>>原有的析构+释放逻辑,引发未定义行为。


内容的提问来源于stack exchange,提问作者Martin Kopecký

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 09:09:05