https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86127
Bug ID: 86127 Summary: STL containers do not satisfy container.requirements.general clause 8 Product: gcc Version: 7.3.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: fidget324 at gmail dot com Target Milestone: --- Clause 23.2.1.8 of n4140 states that for containers which obtain memory using an allocator, "Move constructors obtain an allocator by move construction from the allocator belonging to the container being copied." At least several STL containers in libstdc++ do not satisfy this requirement, and in fact perform several unnecessary copies. I recently reported a similar bug in libc++, which has since been fixed: https://bugs.llvm.org/show_bug.cgi?id=37694 // test.cpp #include <memory> #include <forward_list> #include <vector> #include <map> #include <iostream> template <typename T> class my_allocator { std::allocator<T> __alloc; public: using value_type = T; using propagate_on_container_move_assignment = std::true_type; template <typename U> friend class my_allocator; template <typename U> struct rebind { using other = my_allocator<U>; }; my_allocator() = default; template <typename U> my_allocator(const my_allocator<U> &other) : __alloc(other.__alloc) { std::cout << "template copy constructor\n"; } my_allocator(const my_allocator &other) : __alloc(other.__alloc) { std::cout << "copy constructor\n"; } template <typename U> my_allocator(my_allocator<U> &&other) noexcept : __alloc(other.__alloc) { std::cout << "template move constructor\n"; } my_allocator(my_allocator &&other) noexcept : __alloc(other.__alloc) { std::cout << "move constructor\n"; } value_type *allocate(std::size_t n) { return __alloc.allocate(n); } void deallocate(value_type *p, std::size_t n) { __alloc.deallocate(p, n); } }; int main() { std::cout << "\nforward_list test\n==================\n"; std::forward_list<int, my_allocator<int>> l = {1, 2, 3, 4}; auto l1 = std::move(l); std::cout << "\nmap test\n==================\n"; std::map<int, int, std::less<int>, my_allocator<std::pair<const int, int>>> m = {{1, 2}, {3, 4}}; auto m1 = std::move(m); std::cout << "\nvector test\n==================\n"; std::vector<int, my_allocator<int>> v = {1, 2, 3, 4}; auto v1 = std::move(v); } Compiling with libstdc++ 7.3.1: $ clang++ -std=c++14 test.cpp $ ./a.out forward_list test ================== template copy constructor move constructor template copy constructor template copy constructor template copy constructor template copy constructor move constructor map test ================== copy constructor template copy constructor move constructor move constructor vector test ================== move constructor template copy constructor template copy constructor template copy constructor template copy constructor The same test using the latest 'master' of libc++: $ clang++ -stdlib=libc++ -std=c++14 test.cpp $ ./a.out forward_list test ================== move constructor map test ================== move constructor vector test ================== move constructor