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

PMR分配数据结构构建失败:uses_allocator静态断言错误排查

关于std::pmr容器触发构造静态断言的问题

我尝试实现一个基于std::pmr分配器的数据结构,但编译时触发了静态断言错误,提示:

construction with an allocator must be possible if uses_allocator is true

我猜测问题出在std::pmr::vector尝试调用profile类的带分配器的拷贝构造函数,但我的profile类存在两个问题:1)没有自定义拷贝构造函数;2)默认生成的拷贝构造函数不支持接收分配器参数。但我搞不懂的是:为什么会优先选择拷贝构造函数,而不是默认构造函数?

代码示例

#include <memory_resource>
#include <cstdio>

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

    profile(allocator_type allocator = {})
        :   allocator_{ allocator }
    {}

    allocator_type get_allocator() {
        return allocator_;
    }

    allocator_type allocator_;
};

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

    update(allocator_type allocator = {})
        :   profiles_{ allocator }
    {    }

    allocator_type get_allocator() {
        return profiles_.get_allocator();
    }

    std::pmr::vector<profile> profiles_;
};

struct service
{
    update pending_;
};


int main()
{

}

部分编译错误信息

In file included from /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/memory_resource:36:
In file included from /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/memory_resource.h:41:
/opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/13.0.0/../../../../include/c++/13.0.0/bits/uses_allocator_args.h:72:8: error: static assertion failed due to requirement 'is_constructible_v<profile, const profile &, const std::pmr::polymorphic_allocator<profile> &>': construction with an allocator must be possible if uses_allocator is true
              static_assert(is_constructible_v<_Tp, _Args..., const _Alloc&>,

为什么优先选择拷贝构造函数?

问题出在默认初始化链的隐式检查逻辑:

  1. service默认构造时会初始化pending_,调用update的无参默认构造函数。
  2. update的构造函数用默认allocator_type初始化std::pmr::vector<profile>。
  3. 由于profile定义了allocator_type,std::uses_allocator<profile, allocator_type>::value会被推导为true——这会触发C++标准的分配器扩展构造规则:容器会提前检查元素是否支持带分配器参数的构造方式,包括拷贝构造场景。

std::pmr容器的设计核心是保证分配器在所有元素操作中正确传递,因此即使是空容器初始化,它也会验证元素是否支持带分配器的拷贝构造——因为后续任何元素拷贝操作都需要传递分配器,避免内存资源不匹配。

修复方案

给profile添加带分配器参数的拷贝构造函数(可选补充移动构造函数,符合PMR最佳实践):

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

    profile(allocator_type allocator = {})
        :   allocator_{ allocator }
    {}

    // 带分配器的拷贝构造函数
    profile(const profile& other, allocator_type allocator = {})
        :   allocator_{ allocator }
    {}

    // 可选:带分配器的移动构造函数
    profile(profile&& other, allocator_type allocator = {})
        :   allocator_{ allocator }
    {}

    allocator_type get_allocator() {
        return allocator_;
    }

    allocator_type allocator_;
};

若不需要分配器在拷贝时传递,也可以显式禁用std::uses_allocator的处理(不推荐,违背PMR设计意图):

namespace std {
    template<>
    struct uses_allocator<profile, profile::allocator_type> : false_type {};
}

补充说明

C++标准规定:当类定义了allocator_type且std::uses_allocator为true时,分配感知容器(如std::pmr系列容器)会默认认为该类支持扩展构造——即所有构造场景(包括拷贝、移动)都能接受额外的分配器参数,以此保证内存资源在容器操作中的一致性。

内容的提问来源于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 05:20:28