[Bug libstdc++/86127] New: STL containers do not satisfy container.requirements.general clause 8
fidget324 at gmail dot com
gcc-bugzilla@gcc.gnu.org
Tue Jun 12 22:56:00 GMT 2018
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
More information about the Gcc-bugs
mailing list