flat_foo allocator-extended constructors lack move semantics
[flat.map][flat.multimap] [flat.set][flat.multiset]
Arthur O'Dwyer

Created on 2022-10-25.00:00:00 last changed 3 months ago


Date: 2023-06-14.00:00:00

[ 2023-06-14 Varna ]

Mentioned in P2767R0, but not resolved by it.

Date: 2022-11-15.00:00:00

[ 2022-11-04; Reflector poll ]

Set priority to 2 after reflector poll.

Date: 2022-10-25.00:00:00

Compare [priqueue.cons]'s overload set

priority_queue(const Compare&, const Container&);
priority_queue(const Compare&, Container&&);
template<class Alloc> priority_queue(const Compare&, const Container&, const Alloc&);
template<class Alloc> priority_queue(const Compare&, Container&&, const Alloc&);

against [flat.map]'s overload set

flat_map(key_container_type, mapped_container_type);
template<class Allocator> flat_map(const key_container_type&, const mapped_container_type&, const Allocator& a);

I see two issues here:

  1. (A) The allocator-extended ctor of flat_map always copies the key_container and value_container, when it should be move-enabled.

  2. (B) Almost certainly the Allocator parameter should be named Alloc instead, and there should be a separate "Constructors with allocators" section with wording similar to [priqueue.cons.alloc] explaining that these ctors don't participate in overload resolution unless uses_allocator_v<KeyContainer, Alloc> && uses_allocator_v<MappedContainer, Alloc>.

I suggest this overload set to replace the two overloads above:

flat_map(key_container_type, mapped_container_type);
template<class Alloc> flat_map(const key_container_type&, const mapped_container_type&, const Alloc& a);
template<class Alloc> flat_map(const key_container_type&, mapped_container_type&&, const Alloc& a);
template<class Alloc> flat_map(key_container_type&&, const mapped_container_type&, const Alloc& a);
template<class Alloc> flat_map(key_container_type&&, mapped_container_type&&, const Alloc& a);

This preserves the apparent assumption that KeyContainer(std::move(kc)) is always efficient but KeyContainer(std::move(kc), otheralloc) might not be. Similar wording changes would have to be made to all the flat_foo containers.

Tony Table:

template<class T, class Comp = std::less<T>, class Container = std::pmr::vector<T>>
using pmr_flat_set = std::flat_set<T, Comp, Container>;

std::pmr::vector<pmr_flat_set<int>> vs;
std::pmr::vector<int> data = {1,2,3};

  // constructs-in-place with the argument list (std::move(data), get_allocator())
  // BEFORE: copies (causes heap traffic)
  // AFTER: moves (no heap traffic)
Date User Action Args
2023-06-16 09:31:14adminsetmessages: + msg13637
2022-11-04 20:59:04adminsetmessages: + msg12921
2022-10-25 00:00:00admincreate