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

删除C++17 pmr内存资源分配的多态对象的正确方案

解决方案

当前静态存储内存资源指针的方案存在线程不安全、需手动维护状态易出错的问题,可采用以下两种标准实现解决:


方案1:基类新增虚销毁接口 + 内置存储分配器指针

核心逻辑

  • 给Node基类新增非静态成员,存储当前对象所用的std::pmr::memory_resource指针
  • 新增纯虚destroy()方法,各派生类自行实现销毁逻辑:先调用自身析构,再用对应分配器释放内存
  • 完全移除静态s_deleterResource变量相关逻辑

核心代码修改

struct Node {
    using allocator_type = std::pmr::polymorphic_allocator<Node>;

    std::pmr::string name;
    // 新增:存储当前对象使用的内存资源
    std::pmr::memory_resource* m_res;

    template <class TNode >
    static TNode *create(std::string_view name, std::pmr::memory_resource *res) {
        std::pmr::polymorphic_allocator<TNode> alloc(res);
        auto ptr = alloc.allocate(1);
        ::new (ptr) TNode(alloc, res);
        ptr->name = name;
        return ptr;
    }
    virtual ~Node() {
        std::cerr << "Destructing node: " << name << std::endl;
    }
    // 新增:纯虚销毁接口
    virtual void destroy() noexcept = 0;

protected:
    // 构造函数新增res参数初始化成员
    Node(const allocator_type& alloc, std::pmr::memory_resource* res) : name(alloc), m_res(res) {}
};

struct CompoundNode : Node {
    friend struct Node;
    using allocator_type = std::pmr::polymorphic_allocator<CompoundNode>;

    void addChild(Node *child) {
        m_children.push_back(child);
    }

    ~CompoundNode() override {
        for(auto child : m_children) {
            // 替换原来的delete,调用destroy
            child->destroy();
        }
    }
    // 实现destroy方法
    void destroy() noexcept override {
        std::pmr::polymorphic_allocator<CompoundNode> alloc(m_res);
        this->~CompoundNode();
        alloc.deallocate(this, 1);
    }

protected:
    explicit CompoundNode(const allocator_type& alloc, std::pmr::memory_resource* res) :
        Node(alloc, res), m_children(alloc)
    { }

    std::pmr::vector< Node * > m_children;
};

struct LeafNode : Node {
    friend struct Node;
    using allocator_type = std::pmr::polymorphic_allocator<LeafNode>;

    ~LeafNode() override = default;
    // 实现destroy方法
    void destroy() noexcept override {
        std::pmr::polymorphic_allocator<LeafNode> alloc(m_res);
        this->~LeafNode();
        alloc.deallocate(this, 1);
    }

protected:
    explicit LeafNode(const allocator_type& alloc, std::pmr::memory_resource* res) :
        Node(alloc, res), m_payload(77, alloc) { }

    std::pmr::vector< uint8_t > m_payload;
};

main函数修改

int main() try
{
    std::array< uint8_t, 1000 > buf;
    std::pmr::monotonic_buffer_resource bufferRes(buf.data(), buf.size(),
                                       std::pmr::null_memory_resource());
    VerboseMemResource res("buffered resource", &bufferRes);

    auto root = Node::create<CompoundNode>("root", &res);
    root->addChild(Node::create<LeafNode>("child1", &res));
    root->addChild(Node::create<LeafNode>("child2", &res));

    std::cerr << "Beginning tree deletion..\n";
    // 直接调用destroy,不需要操作静态变量
    root->destroy();
    return 0;
}
catch(std::exception& ex) {
    std::cerr << "Exception: " << ex.what() << std::endl;
    return 1;
}

方案2:返回带自定义删除器的智能指针

不需要修改Node类的虚函数,直接在create方法中返回绑定了删除逻辑的std::unique_ptr,删除器中自带对应内存资源指针,完全遵循RAII规范,无需手动调用销毁方法:

核心代码修改

struct Node {
    using allocator_type = std::pmr::polymorphic_allocator<Node>;
    std::pmr::string name;

    // 修改create返回值为带自定义删除器的unique_ptr
    template <class TNode >
    static auto create(std::string_view name, std::pmr::memory_resource *res) {
        std::pmr::polymorphic_allocator<TNode> alloc(res);
        auto ptr = alloc.allocate(1);
        ::new (ptr) TNode(alloc);
        ptr->name = name;
        // 绑定删除逻辑,自带当前res指针
        auto deleter = [res](TNode* p) noexcept {
            std::pmr::polymorphic_allocator<TNode> alloc(res);
            std::destroy_at(p);
            alloc.deallocate(p, 1);
        };
        return std::unique_ptr<TNode, decltype(deleter)>(ptr, deleter);
    }
    virtual ~Node() {
        std::cerr << "Destructing node: " << name << std::endl;
    }

protected:
    Node(const allocator_type& alloc) : name(alloc) {}
};

struct CompoundNode : Node {
    friend struct Node;
    using allocator_type = std::pmr::polymorphic_allocator<CompoundNode>;

    // 存储带删除器的unique_ptr
    void addChild(std::unique_ptr<Node>&& child) {
        m_children.push_back(std::move(child));
    }

    ~CompoundNode() override = default; // 不需要手动遍历释放,智能指针自动处理

protected:
    explicit CompoundNode(const allocator_type& alloc) :
        Node(alloc), m_children(alloc)
    { }

    std::pmr::vector<std::unique_ptr<Node>> m_children;
};

main函数修改

int main() try
{
    std::array< uint8_t, 1000 > buf;
    std::pmr::monotonic_buffer_resource bufferRes(buf.data(), buf.size(),
                                       std::pmr::null_memory_resource());
    VerboseMemResource res("buffered resource", &bufferRes);

    auto root = Node::create<CompoundNode>("root", &res);
    root->addChild(Node::create<LeafNode>("child1", &res));
    root->addChild(Node::create<LeafNode>("child2", &res));

    std::cerr << "Beginning tree deletion..\n";
    // 不需要手动调用销毁,root离开作用域自动释放所有节点
    return 0;
}
catch(std::exception& ex) {
    std::cerr << "Exception: " << ex.what() << std::endl;
    return 1;
}

选型建议

  • 对性能敏感、节点数量极大的场景选方案1,额外开销仅为每个对象多一个指针的内存占用
  • 优先考虑代码安全性、避免手动管理销毁的场景选方案2,完全符合现代C++的RAII规范,不存在漏释放的风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 19:27:04