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

如何自动初始化含自定义删除器std::shared_ptr的std::array?

问题描述

我正尝试实现一个管理共享资源的类,这些资源的数量在编译时已知,且需在资源释放、析构函数调用前执行自定义操作。我决定采用std::array<std::shared_ptr<...>>作为成员,并搭配自定义删除器:

template <size_t NUM_RESOURCES> class QuirkyMachine {
protected:
    using ResourceDeleter = decltype([](auto resource) { 
        someCustomAction(resource); });
    std::array<std::shared_ptr<Resource>, NUM_RESOURCES> _resources;
};

请问是否有办法让该数组自动构造使用ResourceDeleter的std::shared_ptr实例,无需显式构造每个指针并通过初始化列表传递?我希望尽可能使用标准库,且需要一个编译时大小固定的集合。

解决方案

当然可以实现,核心思路是利用编译时生成的初始化逻辑或标准库算法,批量构造带自定义删除器的std::shared_ptr,同时保留std::array的编译期固定大小特性,以下是两种可行方案:

方案1:编译期索引遍历初始化(纯编译期逻辑)

借助std::index_sequence生成编译期索引,通过参数包展开批量初始化数组元素,完全在编译阶段完成构造逻辑:

#include <array>
#include <memory>
#include <utility>

// 假设的资源类型与自定义操作
struct Resource {};
void someCustomAction(Resource* resource) {}

template <size_t NUM_RESOURCES> 
class QuirkyMachine {
protected:
    using ResourceDeleter = decltype([](auto* resource) { 
        someCustomAction(resource); 
    });
    std::array<std::shared_ptr<Resource>, NUM_RESOURCES> _resources;

    // 辅助构造函数:利用编译期索引序列批量初始化
    template <size_t... Idx>
    QuirkyMachine(std::index_sequence<Idx...>)
        : _resources{ (std::shared_ptr<Resource>(nullptr, ResourceDeleter{}))... }
    {}

public:
    QuirkyMachine() : QuirkyMachine(std::make_index_sequence<NUM_RESOURCES>{}) {}
};

这里std::make_index_sequence<NUM_RESOURCES>会生成0到NUM_RESOURCES-1的编译期索引列表,再通过参数包展开(std::shared_ptr<Resource>(nullptr, ResourceDeleter{}))...,自动为数组的每个元素构造带自定义删除器的空智能指针。

方案2:标准库算法批量填充(运行时简洁实现)

先给带自定义删除器的智能指针定义别名,再用std::fill或std::generate完成批量初始化,代码更简洁直观:

#include <array>
#include <memory>
#include <algorithm>

struct Resource {};
void someCustomAction(Resource* resource) {}

template <size_t NUM_RESOURCES> 
class QuirkyMachine {
protected:
    using ResourceDeleter = decltype([](auto* resource) { 
        someCustomAction(resource); 
    });
    // 定义带指定删除器的智能指针别名
    using SharedResource = std::shared_ptr<Resource>;
    std::array<SharedResource, NUM_RESOURCES> _resources;

public:
    QuirkyMachine() {
        // 批量填充空的带删除器智能指针
        std::fill(_resources.begin(), _resources.end(), SharedResource(nullptr, ResourceDeleter{}));
    }
};

如果需要在初始化时就分配资源(而非空指针),可以替换为std::generate调用资源创建函数:

// 假设的资源创建函数
Resource* createResource() { return new Resource{}; }

// 构造函数内修改为:
std::generate(_resources.begin(), _resources.end(), [](){
    return SharedResource(createResource(), ResourceDeleter{});
});

注意事项

  • 当自定义删除器是无捕获lambda时,std::shared_ptr的内存占用和普通版本一致,不会有额外开销;若lambda带有捕获变量,删除器会占用额外内存空间,需要注意成本。
  • 若要求完全编译期完成初始化,优先选择方案1;若追求代码简洁,方案2的标准库算法实现更易维护。

内容的提问来源于stack exchange,提问作者pSoLT

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 14:47:35