带polymorphic_allocator的嵌套pmr vector无法用emplace_back构造的原因
先看这段会报错的代码:
std::pmr::vector<std::pmr::vector<int>> outer_vec(std::pmr::get_default_resource()); outer_vec.emplace_back(std::pmr::get_default_resource());
运行后触发断言错误:
static assertion failed: construction with an allocator must be possible if uses_allocator is true
但以下几种类似场景都能正常运行:
场景1:先构造内层vector再push_back
std::pmr::vector<std::pmr::vector<int>> outer_vec(std::pmr::get_default_resource()); std::pmr::vector<int> inner_vec(std::pmr::get_default_resource()); outer_vec.push_back(std::move(inner_vec));
场景2:内层是非pmr vector时调用emplace_back
std::pmr::vector<std::vector<int>> outer_vec(std::pmr::get_default_resource()); outer_vec.emplace_back();
场景3:外层是非pmr vector时调用emplace_back
std::vector<std::pmr::vector<int>> vec; vec.emplace_back(std::pmr::get_default_resource());
核心原因解析
问题出在pmr容器的allocator传播规则和emplace_back的参数处理逻辑上:
pmr容器的uses_allocator特性:
std::pmr::vector本质是std::vector<T, std::pmr::polymorphic_allocator<T>>的别名。对于外层的pmr::vector<pmr::vector<int>>,其分配器是polymorphic_allocator<pmr::vector<int>>。根据C++标准的std::uses_allocator规则,pmr::vector<int>满足uses_allocator_v<pmr::vector<int>, polymorphic_allocator<...>> == true——因为它本身就是基于polymorphic_allocator实现的容器。emplace_back的参数传递逻辑:
当外层pmr容器调用emplace_back时,会自动尝试将自身的分配器传递给内层元素的构造函数。此时你传入了一个memory_resource*作为构造参数,容器会尝试用「外层分配器 + 传入的memory_resource*」来构造内层pmr::vector<int>,但内层pmr::vector<int>并没有这样的构造函数:它要么接受单个memory_resource*,要么接受单个polymorphic_allocator<T>,但不支持两者同时作为参数,这直接触发了断言检查。对比场景的差异:
- 场景1:
push_back是移动已构造完成的内层vector,外层容器不需要参与内层的构造过程,自然不会传递分配器,因此无冲突。 - 场景2:内层是普通
std::vector<int>,它可以接受polymorphic_allocator作为构造参数(符合uses_allocator的要求),所以外层传递分配器后能正常构造。 - 场景3:外层是普通
std::vector,其分配器是std::allocator,而uses_allocator_v<pmr::vector<int>, std::allocator<int>> == false,因此外层容器不会传递自身的分配器,直接用你传入的memory_resource*构造内层pmr vector,没有问题。
- 场景1:
内容的提问来源于stack exchange,提问作者Zereges

