type requirements for std::vector

前端 未结 5 1457
夕颜
夕颜 2020-12-21 17:17

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:

相关标签:
5条回答
  • 2020-12-21 17:23

    void resize(size_type) requires CopyInsertable, which means that an allocator should be able to construct-copy the type:

    ::new((void*)p)A(A());
    

    This means that a copy-constructor is required. You should be able to bypass this with a custom allocator:

    struct Allocator: public std::allocator<A> {
      void construct(A *, const A &) { }
    };
    

    However libstdc++ does not respect this; see Should (in C++11) std::vector::resize(size_type) work for the default constructible value_type int[4]?

    0 讨论(0)
  • 2020-12-21 17:29

    On ideone, I see one call to the default constructor. But four objects are being created, the others have to be constructed somehow. Actually, a prototype object is default constructed and then copied four times.

    The C++11 Standard (section 23.3.6.3) says that "value initialized" objects will be inserted, but also requires that the type is copyable:

    void resize(size_type sz);

    • Effects: If sz <= size(), equivalent to erase(begin() + sz, end());. If size() < sz, appends sz - size() value-initialized elements to the sequence.
    • Requires: T shall be CopyInsertable into *this.

    There's no compiler bug here; it is your code which is wrong.

    0 讨论(0)
  • 2020-12-21 17:36

    To use a class in a vector it should have a copy constructor/assignment operator or a noexcept move constructor/assignment operator. GCC is quite correct not to compile your example which doesn't have any of these.

    How would you except the vector to do anything without being able to copy or move what it contains?

    The reason that the first example works is that since you didn't define any copy or move constructors or assignment operators, you get the defaults. In the second example, since you explicitly deleted the copy constructor, you don't get any automatically generated constructors or assignment operators.

    0 讨论(0)
  • 2020-12-21 17:38

    In C++11, the requirements depend on the operations performed. In the case of std::vector<T>::resize(), the requirement on T is that it be CopyInsertable into the vector.

    From §23.3.6.3

    void resize(size_type sz);

    ....

    Requires: T shall be CopyInsertable into *this.

    0 讨论(0)
  • 2020-12-21 17:39

    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.

    0 讨论(0)
提交回复
热议问题