[llvm-bugs] [Bug 37694] New: std::vector does not satisfy container.requirements.general clause 8

via llvm-bugs llvm-bugs at lists.llvm.org
Tue Jun 5 13:45:19 PDT 2018


https://bugs.llvm.org/show_bug.cgi?id=37694

            Bug ID: 37694
           Summary: std::vector does not satisfy
                    container.requirements.general clause 8
           Product: libc++
           Version: 6.0
          Hardware: PC
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: All Bugs
          Assignee: unassignedclangbugs at nondot.org
          Reporter: sdconsta at syr.edu
                CC: llvm-bugs at lists.llvm.org, mclow.lists at gmail.com

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." This requirements does
not hold for std::vector:

#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;

  my_allocator() = default;
  my_allocator(const my_allocator &other) : __alloc(other.__alloc) {
    std::cout << "copy 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::forward_list<int, my_allocator<int>> l = {1, 2, 3, 4};
  auto l1 = std::move(l);
  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::vector<int, my_allocator<int>> v = {1, 2, 3, 4};
  auto v1 = std::move(v);
}

(compiled only with -std=c++14 on clang++) prints:

move constructor
move constructor
copy constructor

If we instead delete the copy constructor, clang emits

/usr/local/Cellar/llvm/6.0.0/include/c++/v1/memory:2097:9: error: call to
deleted constructor of 'my_allocator<int>'
      : __value_(_VSTD::forward<_Up>(__u)){};
        ^        ~~~~~~~~~~~~~~~~~~~~~~~~
/usr/local/Cellar/llvm/6.0.0/include/c++/v1/memory:2197:42: note: in
instantiation of function template specialization
'std::__1::__compressed_pair_elem<my_allocator<int>, 1,
      false>::__compressed_pair_elem<const my_allocator<int> &, void>'
requested here
      : _Base1(std::forward<_U1>(__t1)), _Base2(std::forward<_U2>(__t2)) {}
                                         ^
/usr/local/Cellar/llvm/6.0.0/include/c++/v1/vector:432:7: note: in
instantiation of function template specialization
'std::__1::__compressed_pair<int *, my_allocator<int>
      >::__compressed_pair<nullptr_t, const my_allocator<int> &>' requested
here
      __end_cap_(nullptr, __a)
      ^
/usr/local/Cellar/llvm/6.0.0/include/c++/v1/vector:1242:7: note: in
instantiation of member function 'std::__1::__vector_base<int,
my_allocator<int> >::__vector_base' requested here
    : __base(_VSTD::move(__x.__alloc()))
      ^
test.cpp:35:13: note: in instantiation of member function
'std::__1::vector<int, my_allocator<int> >::vector' requested here
  auto v1 = std::move(v);
            ^
test.cpp:15:3: note: 'my_allocator' has been explicitly marked deleted here
  my_allocator(const my_allocator &) = delete;
  ^
1 error generated.

I believe the problem is that there is no constructor for __vector_base which
accepts an rvalue reference to the allocator. Hence the copy constructor is
being called instead.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20180605/76f4d9d9/attachment.html>


More information about the llvm-bugs mailing list