Search code examples
c++constructorc++11allocationstdvector

type requirements for std::vector<type>


I am still confused about the requirements for a type to be used with a std::vector in C++11, but this may be caused by a buggy compiler (gcc 4.7.0). This code:

struct A {
  A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
  int X;
};

int main()
{
  std::vector<A> a;
  a.resize(4);
}

works fine and produces the expected output, indicating that the default ctor (explicitly given) is called (and not an implicit copy ctor). However, if I add a deleted copy ctor to the class, viz

struct A {
  A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
  A(A const&) = delete;
  int X;
};

gcc 4.7.0 does not compile, but tries to use the deleted ctor. Is that correct behaviour or a bug? If the former, how to get the code working?


Solution

  • The C++11 standard does indeed require CopyInsertable as others have pointed out. However this is a bug in the C++11 standard. This has since been corrected in N3376 to MoveInsertable and DefaultInsertable.

    The vector<T, A>::resize(n) member function requires MoveInsertable and DefaultInsertable. These roughly translate to DefaultConstructible and MoveConstructible when the allocator A uses the default construct definitions.

    The following program compiles using clang/libc++:

    #include <vector>
    #include <iostream>
    
    struct A {
      A() : X(0) { std::cerr<<" A::A(); this="<<this<<'\n'; }
      A(A&&) = default;
      int X;
    };
    
    int main()
    {
      std::vector<A> a;
      a.resize(4);
    }
    

    and for me prints out:

     A::A(); this=0x7fcd634000e0
     A::A(); this=0x7fcd634000e4
     A::A(); this=0x7fcd634000e8
     A::A(); this=0x7fcd634000ec
    

    If you remove the move constructor above and replace it with a deleted copy constructor, A is no longer MoveInsertable/MoveConstructible as move construction then attempts to use the deleted copy constructor, as correctly demonstrated in the OP's question.