使用pmr与默认构造函数时vector::emplace_back()参数异常的原因与解决
PMR Vector emplace_back默认初始化对象时编译报错
尝试向PMR vector中emplace_back一个默认初始化的profile类对象,由于vector已用分配器初始化,容器会尝试为元素构造函数传入自身的分配器参数,但此时出现额外参数,导致编译报错。
示例代码
#include <memory_resource> #include <cstdio> struct profile { using allocator_type = std::pmr::polymorphic_allocator<std::byte>; profile(allocator_type allocator = {}) {} }; struct update { using allocator_type = std::pmr::polymorphic_allocator<std::byte>; update(allocator_type allocator = {}) : profiles_( allocator ) { } std::pmr::vector<profile> profiles_; }; int main() { update u; u.profiles_.emplace_back(); }
关键错误片段
stl_construct.h: In substitution of 'template<class _Tp, class ... _Args> constexpr decltype (::new(void*(0)) _Tp) std::construct_at(_Tp*, _Args&& ...) [with _Tp = profile; _Args = {profile, const std::pmr::polymorphic_allocator<profile>&}]':
原因分析
- PMR容器(比如
std::pmr::vector)在构造元素时,会自动尝试将自身的分配器传递给元素的构造函数,这是PMR容器的特性。 profile类定义的allocator_type是std::pmr::polymorphic_allocator<std::byte>,但std::pmr::vector<profile>使用的分配器是std::pmr::polymorphic_allocator<profile>(PMR容器会自动将分配器的value_type转换为元素类型)。- 调用
emplace_back()时,编译器尝试将vector的分配器转换为profile的allocator_type,但错误地触发了意外的构造匹配:把默认构造的临时profile对象和转换后的分配器一起作为参数传入,导致profile的构造函数收到两个参数,超出了定义的重载范围。
解决方法
方法1:统一分配器的value_type
将profile的allocator_type改为和vector一致的std::pmr::polymorphic_allocator<profile>,让容器传递的分配器直接匹配构造函数参数,避免类型转换带来的错误:
#include <memory_resource> #include <cstdio> struct profile { using allocator_type = std::pmr::polymorphic_allocator<profile>; profile(allocator_type allocator = {}) {} }; struct update { using allocator_type = std::pmr::polymorphic_allocator<std::byte>; update(allocator_type allocator = {}) : profiles_(allocator) { } std::pmr::vector<profile> profiles_; }; int main() { update u; u.profiles_.emplace_back(); }
方法2:显式避免容器自动注入分配器
调用push_back({})代替emplace_back(),或者使用std::piecewise_construct显式指定空参数列表,阻止容器自动传入分配器:
// 修改main函数中的调用 int main() { update u; u.profiles_.push_back({}); // 或者使用piecewise_construct: // u.profiles_.emplace_back(std::piecewise_construct, std::tuple<>{}, std::tuple<>{}); }
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

