c++c++20copy-constructorallocatorc++pmr

construction with an allocator must be possible if uses_allocator is true


I'm trying to create a pmr-allocated datastructure (compare code below). This however fails with an awful long error message and I can't quite track the root of it. At the end is a static_assert which says construction with an allocator must be possible if uses_allocator is true.

As far as I can tell, std::pmr::vector is trying to call the copy constructor of profile with an allocator which fails because 1) I didn't define a copy constructor and 2) the default copy constructor doesn't take into account allocator construction. However: Why is the copy constructor being selected in the first place? How did I urge std::pmr::vector to select the copy constructor over the default one?

Demo

#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()
{

}

Partial error (check above link to see whole traceback):

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&>,

Solution

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

    Converts allocator to profile and initializes profiles_ with an initializer_list containing single element, which is getting copied.

    Either change {} to () or make profile constructor explicit (you might want to provide separate non-explicit default constructor in this case)