[Bug libstdc++/86127] New: STL containers do not satisfy container.requirements.general clause 8

2018-06-12 Thread fidget324 at gmail dot com
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

2018-06-13 Thread fidget324 at gmail dot com
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

2018-06-13 Thread fidget324 at gmail dot com
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

2017-12-05 Thread fidget324 at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79094

--- Comment #2 from Scott Constable  ---
This is still an issue in 7.2.0.