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

pmr容器emplace_back含allocator_type类触发uses_allocator静态断言失败

问题:PMR容器emplace_back触发未预期的构造函数调用错误

我定义了PmrCustomer类,该类已实现uses-allocator构造协议——包含allocator_type类型定义,且提供了带尾部分配器参数的构造函数,但未显式定义拷贝构造函数或移动构造函数。随后创建pmr::vector容器,尝试调用emplace_back传入pmr::string对象,原本以为会调用我提供的唯一构造函数,但编译时出现错误。显式添加带尾部分配器的拷贝构造和移动构造函数后问题解决,想了解未显式提供这些构造函数时错误产生的原因。

代码示例

#include <string>
#include <memory_resource>
#include <iostream>

class PmrCustomer
{
private:
    std::pmr::string name;  
public:
    using allocator_type = std::pmr::polymorphic_allocator<char>;

    PmrCustomer(std::pmr::string n, allocator_type alloc = {}) : name{std::move(n), alloc}, allocator_(alloc) {
    }
    

    //PmrCustomer(const PmrCustomer& c, allocator_type alloc) : name{c.name, alloc} {
    //}
    //PmrCustomer(PmrCustomer&& c, allocator_type alloc) : name{std::move(c.name), alloc} {
    //}

    // setter/getter:
    void setName(std::pmr::string s) {
        name = std::move(s);
    }
    std::pmr::string getName() const {
        return name;
    }
    std::string getNameAsString() const {
        return std::string{name};
    }
    allocator_type allocator_;
};


int main()
{
    std::pmr::vector<PmrCustomer> coll(std::pmr::get_default_resource());
    coll.reserve(100);               
    
    std::pmr::string  c2 {"peter"};
    coll.emplace_back(c2);

    for (const auto& cust : coll) {
        std::cout << cust.getName() << '\n';
    }
}

编译环境

  • Ubuntu20.04
  • gcc-9
  • 编译选项:-std=c++17

报错详情

In file included from /usr/include/c++/9/memory:77,
                 from /usr/include/c++/9/memory_resource:37,
                 from d.cpp:2:
/usr/include/c++/9/bits/uses_allocator.h: In instantiation of ‘struct std::__uses_alloc<true, PmrCustomer, std::pmr::polymorphic_allocator<PmrCustomer>, PmrCustomer>’:
/usr/include/c++/9/type_traits:1294:12:   required from ‘struct std::is_base_of<std::__uses_alloc0, std::__uses_alloc<true, PmrCustomer, std::pmr::polymorphic_allocator<PmrCustomer>, PmrCustomer> >’
/usr/include/c++/9/type_traits:2991:25:   required from ‘constexpr const bool std::is_base_of_v<std::__uses_alloc0, std::__uses_alloc<true, PmrCustomer, std::pmr::polymorphic_allocator<PmrCustomer>, PmrCustomer> >’
/usr/include/c++/9/memory_resource:243:18:   required from ‘typename std::pmr::polymorphic_allocator<_Tp>::__not_pair<_Up>::type std::pmr::polymorphic_allocator<_Tp>::construct(_Tp1*, _Args&& ...) [with _Tp1 = PmrCustomer; _Args = {PmrCustomer}; _Tp = PmrCustomer; typename std::pmr::polymorphic_allocator<_Tp>::__not_pair<_Up>::type = void]’
/usr/include/c++/9/bits/alloc_traits.h:244:4:   required from ‘static std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = PmrCustomer; _Args = {PmrCustomer}; _Alloc = std::pmr::polymorphic_allocator<PmrCustomer>; std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> = void]’
/usr/include/c++/9/bits/alloc_traits.h:350:16:   required from ‘static decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = PmrCustomer; _Args = {PmrCustomer}; _Alloc = std::pmr::polymorphic_allocator<PmrCustomer>; decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = void]’
/usr/include/c++/9/bits/stl_uninitialized.h:293:25:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = std::move_iterator<PmrCustomer*>; _ForwardIterator = PmrCustomer*; _Allocator = std::pmr::polymorphic_allocator<PmrCustomer>]’
/usr/include/c++/9/bits/stl_vector.h:1511:35:   required from ‘std::vector<_Tp, _Alloc>::pointer std::vector<_Tp, _Alloc>::_M_allocate_and_copy(std::vector<_Tp, _Alloc>::size_type, _ForwardIterator, _ForwardIterator) [with _ForwardIterator = std::move_iterator<PmrCustomer*>; _Tp = PmrCustomer; _Alloc = std::pmr::polymorphic_allocator<PmrCustomer>; std::vector<_Tp, _Alloc>::pointer = PmrCustomer*; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/9/bits/vector.tcc:85:14:   required from ‘void std::vector<_Tp, _Alloc>::reserve(std::vector<_Tp, _Alloc>::size_type) [with _Tp = PmrCustomer; _Alloc = std::pmr::polymorphic_allocator<PmrCustomer>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
d.cpp:77:21:   required from here
/usr/include/c++/9/bits/uses_allocator.h:98:53: error: static assertion failed: construction with an allocator must be possible if uses_allocator is true
   98 |    is_constructible<_Tp, _Args..., const _Alloc&>>::value,
      |                                                     ^~~~~
In file included from d.cpp:2:
/usr/include/c++/9/memory_resource: In instantiation of ‘typename std::pmr::polymorphic_allocator<_Tp>::__not_pair<_Up>::type std::pmr::polymorphic_allocator<_Tp>::construct(_Tp1*, _Args&& ...) [with _Tp1 = PmrCustomer; _Args = {PmrCustomer}; _Tp = PmrCustomer; typename std::pmr::polymorphic_allocator<_Tp>::__not_pair<_Up>::type = void]’:
/usr/include/c++/9/bits/alloc_traits.h:244:4:   required from ‘static std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> std::allocator_traits<_Alloc>::_S_construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = PmrCustomer; _Args = {PmrCustomer}; _Alloc = std::pmr::polymorphic_allocator<PmrCustomer>; std::_Require<typename std::allocator_traits<_Alloc>::__construct_helper<_Tp, _Args>::type> = void]’
/usr/include/c++/9/bits/alloc_traits.h:350:16:   required from ‘static decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) std::allocator_traits<_Alloc>::construct(_Alloc&, _Tp*, _Args&& ...) [with _Tp = PmrCustomer; _Args = {PmrCustomer}; _Alloc = std::pmr::polymorphic_allocator<PmrCustomer>; decltype (std::allocator_traits<_Alloc>::_S_construct(__a, __p, (forward<_Args>)(std::allocator_traits::construct::__args)...)) = void]’
/usr/include/c++/9/bits/stl_uninitialized.h:293:25:   required from ‘_ForwardIterator std::__uninitialized_copy_a(_InputIterator, _InputIterator, _ForwardIterator, _Allocator&) [with _InputIterator = std::move_iterator<PmrCustomer*>; _ForwardIterator = PmrCustomer*; _Allocator = std::pmr::polymorphic_allocator<PmrCustomer>]’
/usr/include/c++/9/bits/stl_vector.h:1511:35:   required from ‘std::vector<_Tp, _Alloc>::pointer std::vector<_Tp, _Alloc>::_M_allocate_and_copy(std::vector<_Tp, _Alloc>::size_type, _ForwardIterator, _ForwardIterator) [with _ForwardIterator = std::move_iterator<PmrCustomer*>; _Tp = PmrCustomer; _Alloc = std::pmr::polymorphic_allocator<PmrCustomer>; std::vector<_Tp, _Alloc>::pointer = PmrCustomer*; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
/usr/include/c++/9/bits/vector.tcc:85:14:   required from ‘void std::vector<_Tp, _Alloc>::reserve(std::vector<_Tp, _Alloc>::size_type) [with _Tp = PmrCustomer; _Alloc = std::pmr::polymorphic_allocator<PmrCustomer>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]’
d.cpp:77:21:   required from here
/usr/include/c++/9/memory_resource:249:6: error: no matching function for call to ‘PmrCustomer::PmrCustomer(PmrCustomer, std::pmr::polymorphic_allocator<PmrCustomer>&)’
  249 |      ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this);
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
d.cpp:50:5: note: candidate: ‘PmrCustomer::PmrCustomer(std::pmr::string, PmrCustomer::allocator_type)’
   50 |     PmrCustomer(std::pmr::string n, allocator_type alloc = {}) : name{std::move(n), alloc}, allocator_(alloc) {
      |     ^~~~~~~~~~~
d.cpp:50:34: note:   no known conversion for argument 1 from ‘PmrCustomer’ to ‘std::pmr::string’ {aka ‘std::__cxx11::basic_string<char, std::char_traits<char>, std::pmr::polymorphic_allocator<char> >’}
   50 |     PmrCustomer(std::pmr::string n, allocator_type alloc = {}) : name{std::move(n), alloc}, allocator_(alloc) {
      |                 ~~~~~~~~~~~~~~~~~^
d.cpp:43:7: note: candidate: ‘PmrCustomer::PmrCustomer(const PmrCustomer&)’
   43 | class PmrCustomer
      |       ^~~~~~~~~~~
d.cpp:43:7: note:   candidate expects 1 argument, 2 provided
d.cpp:43:7: note: candidate: ‘PmrCustomer::PmrCustomer(PmrCustomer&&)’
d.cpp:43:7: note:   candidate expects 1 argument, 2 provided

错误原因解析

  1. 错误触发点在reserve的内存重分配逻辑
    你调用coll.reserve(100)时,vector会尝试分配更大的内存块。虽然此时容器为空,但编译器在实例化vector的内存重分配模板时,会检查如何构造新内存中的元素——包括从旧元素移动/拷贝的场景。PMR分配器会严格遵循uses-allocator构造协议,尝试在构造对象时自动追加分配器参数。

  2. 默认生成的拷贝/移动构造不兼容uses-allocator协议
    因为你的类定义了allocator_type,标准库会判定它支持uses-allocator构造。但编译器自动生成的默认拷贝构造是PmrCustomer(const PmrCustomer&),默认移动构造是PmrCustomer(PmrCustomer&&),都只接受1个参数。当标准库尝试以PmrCustomer(源对象, 分配器)的形式构造新对象时,找不到匹配的构造函数,直接触发编译错误。

  3. 静态断言的触发逻辑
    标准库的uses_allocator相关模板会做静态检查:如果一个类标记为支持分配器(即存在allocator_type),那么必须能以「原有构造参数 + 分配器」的形式构造对象。当检查到无法用PmrCustomer对象加分配器构造新实例时,就会触发uses_allocator.h中的静态断言,提示构造失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 15:10:16