[Bug libstdc++/86127] New: STL containers do not satisfy container.requirements.general clause 8
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 #include #include #include #include template class my_allocator { std::allocator __alloc; public: using value_type = T; using propagate_on_container_move_assignment = std::true_type; template friend class my_allocator; template struct rebind { using other = my_allocator; }; my_allocator() = default; template my_allocator(const my_allocator &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 my_allocator(my_allocator &&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> l = {1, 2, 3, 4}; auto l1 = std::move(l); std::cout << "\nmap test\n==\n"; std::map, my_allocator>> m = {{1, 2}, {3, 4}}; auto m1 = std::move(m); std::cout << "\nvector test\n==\n"; std::vector> 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
[Bug libstdc++/86127] STL containers do not satisfy container.requirements.general clause 8
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86127 --- Comment #7 from Scott Constable --- (In reply to Jonathan Wakely from comment #1) > The allocator requirements say that move construction must be equivalent to > copy construction, and allocators should be cheap to copy anyway. I don't > consider this a bug. To be nitpicky, it looks like this equivalence requirement was introduced recently in the C++20 draft. I'm compiling using C++14. I agree that allocators should be cheap to copy, but as a general principle I think that all objects should be copied only when necessary. This is the behavior I have observed in STL containers in libc++, as shown in my example above. It just makes sense to me that when an STL container is moved, its allocator should be moved, and no copying should be performed.
[Bug libstdc++/86127] STL containers do not satisfy container.requirements.general clause 8
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86127 --- Comment #9 from Scott Constable --- (In reply to Jonathan Wakely from comment #8) > (In reply to Scott Constable from comment #7) > > (In reply to Jonathan Wakely from comment #1) > > > The allocator requirements say that move construction must be equivalent > > > to > > > copy construction, and allocators should be cheap to copy anyway. I don't > > > consider this a bug. > > > > To be nitpicky, it looks like this equivalence requirement was introduced > > recently in the C++20 draft. I'm compiling using C++14. > > It's a defect report, so applies to previous standards. > > https://wg21.link/lwg2593 > > Applying that change selectively would be madness. Ah, I wasn't aware this was a defect correction. I should have figured that out myself. > > > I agree that allocators should be cheap to copy, but as a general principle > > I think that all objects should be copied only when necessary. This is the > > behavior I have observed in STL containers in libc++, as shown in my example > > above. It just makes sense to me that when an STL container is moved, its > > allocator should be moved, and no copying should be performed. > > And that's exactly what libstdc++ does. Your test fails to distinguish > between copies/moves performed during move construction and other operations. I misstated my argument here. The STL container move invokes one move from the allocator, and this is correct. What I don't understand is why the other copies, e.g. from the container default constructor and destructor, are necessary. Particularly when libc++ does not exhibit this behavior.
[Bug c++/79094] Pack expansion in using-declaration rejects an attempt to inherit a pack of constructors
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79094 --- Comment #2 from Scott Constable --- This is still an issue in 7.2.0.