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:
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]?
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 toerase(begin() + sz, end());
. Ifsize() < sz
, appendssz - size()
value-initialized elements to the sequence.- Requires:
T
shall beCopyInsertable
into*this
.
There's no compiler bug here; it is your code which is wrong.
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.
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 beCopyInsertable
into *this.
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.