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

如何使用pmr分配器深拷贝指向pmr资源的unique_ptr?

PMR环境下unique_ptr深拷贝的分配器适配方案

问题背景

用多态内存资源(PMR)重写库的时候碰到个标准没覆盖的坑:我的类里存了个unique_ptr,指向用PMR分配的资源(比如pmr::vector),拷贝构造时得做深拷贝。本来想直接用分配器的new_object()创建对象,再交给unique_ptr管理,但遇到两个问题:

  1. 分配器不是合法的删除函子,没法直接当unique_ptr的删除器用——它没重载operator()来执行删除操作
  2. delete_object()是分配器的非静态成员函数,不能直接传给unique_ptr当删除逻辑

举个出错的代码例子:

#include <memory_resource>
#include <memory>
#include <vector>

class MyClass {
public:
    using Allocator = std::pmr::polymorphic_allocator<std::byte>;

    MyClass(Allocator alloc = {}) : alloc_(alloc) {
        // 用new_object创建pmr::vector,但unique_ptr的默认删除器会用普通delete,不对
        vec_ = std::unique_ptr<std::pmr::vector<int>>(alloc_.new_object<std::pmr::vector<int>>(alloc_));
    }

    MyClass(const MyClass& other) : alloc_(other.alloc_) {
        // 尝试深拷贝,但同样面临删除器不匹配的问题
        vec_ = std::unique_ptr<std::pmr::vector<int>>(alloc_.new_object<std::pmr::vector<int>>(*other.vec_, alloc_));
    }

    ~MyClass() {
        // 只能手动调用delete_object,没法让unique_ptr自动处理
        if (vec_) {
            alloc_.delete_object(vec_.release());
        }
    }

private:
    Allocator alloc_;
    std::unique_ptr<std::pmr::vector<int>> vec_;
};

编译器会报类似错误:

error: static assertion failed: unique_ptr's deleter must be invocable with a pointer to the type
note: 'std::default_delete<std::pmr::vector>' is not callable with an argument of type 'std::pmr::vector*'

解决方案:自定义PMR适配删除器

核心思路是写个自定义删除器,把PMR分配器和delete_object()的调用逻辑绑定起来,让unique_ptr能正确调用PMR的释放逻辑。

1. 实现自定义删除器

这个删除器要持有PMR分配器,并重载operator()来调用分配器的delete_object():

template <typename T>
struct PMRDeleter {
    using Allocator = std::pmr::polymorphic_allocator<std::byte>;

    PMRDeleter() = default;
    explicit PMRDeleter(Allocator alloc) : alloc_(std::move(alloc)) {}

    void operator()(T* ptr) const {
        if (ptr) {
            alloc_.delete_object(ptr);
        }
    }

private:
    Allocator alloc_;
};

2. 修改unique_ptr的类型

把原来的unique_ptr改成带自定义删除器的版本:

using VecPtr = std::unique_ptr<std::pmr::vector<int>, PMRDeleter<std::pmr::vector<int>>>;
VecPtr vec_;

3. 调整构造函数逻辑

创建unique_ptr时,要把分配器同时传给new_object()和删除器,确保创建和释放用的是同一个PMR资源:

// 默认构造函数
MyClass(Allocator alloc = {}) : alloc_(alloc), vec_(alloc.new_object<std::pmr::vector<int>>(alloc), PMRDeleter<std::pmr::vector<int>>(alloc)) {}

// 拷贝构造函数(深拷贝)
MyClass(const MyClass& other) : alloc_(other.alloc_) {
    // 用当前对象的分配器创建新的vector,并拷贝原数据
    vec_ = VecPtr(alloc_.new_object<std::pmr::vector<int>>(*other.vec_, alloc_), PMRDeleter<std::pmr::vector<int>>(alloc_));
}

4. 移除手动析构逻辑

现在unique_ptr会自动调用自定义删除器来释放资源,所以可以删掉原来手动调用delete_object()的析构函数。

完整可运行代码

#include <memory_resource>
#include <memory>
#include <vector>

template <typename T>
struct PMRDeleter {
    using Allocator = std::pmr::polymorphic_allocator<std::byte>;

    PMRDeleter() = default;
    explicit PMRDeleter(Allocator alloc) : alloc_(std::move(alloc)) {}

    void operator()(T* ptr) const {
        if (ptr) {
            alloc_.delete_object(ptr);
        }
    }

private:
    Allocator alloc_;
};

class MyClass {
public:
    using Allocator = std::pmr::polymorphic_allocator<std::byte>;
    using VecPtr = std::unique_ptr<std::pmr::vector<int>, PMRDeleter<std::pmr::vector<int>>>;

    MyClass(Allocator alloc = {}) : alloc_(alloc), vec_(create_vec(alloc)) {}

    // 深拷贝构造
    MyClass(const MyClass& other) : alloc_(other.alloc_) {
        vec_ = create_vec(alloc_, *other.vec_);
    }

    // 移动构造和赋值默认即可
    MyClass(MyClass&&) noexcept = default;
    MyClass& operator=(MyClass&&) noexcept = default;

    // 拷贝赋值运算符
    MyClass& operator=(const MyClass& other) {
        if (this != &other) {
            alloc_ = other.alloc_;
            vec_ = create_vec(alloc_, *other.vec_);
        }
        return *this;
    }

private:
    // 封装vector创建逻辑,减少重复代码
    static VecPtr create_vec(Allocator alloc, const std::pmr::vector<int>& init = {}) {
        if (init.empty()) {
            return VecPtr(alloc.new_object<std::pmr::vector<int>>(alloc), PMRDeleter<std::pmr::vector<int>>(alloc));
        } else {
            return VecPtr(alloc.new_object<std::pmr::vector<int>>(init, alloc), PMRDeleter<std::pmr::vector<int>>(alloc));
        }
    }

    Allocator alloc_;
    VecPtr vec_;
};

额外说明

  • polymorphic_allocator是轻量级可拷贝的,拷贝后依然指向同一个内存资源,所以存在删除器里完全安全。
  • 如果想更轻量,也可以在删除器里存std::pmr::memory_resource*代替整个分配器,但要保证内存资源的生命周期比unique_ptr长。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 04:15:41