So taking into account the following comment by the OP:
vector vec(5); is not UB (is it?) and we tend to think that (5) and
(5, S()) ought to do the same thing. I could see this mistake being
made by accident quite easily.
The question boils down to if:
vector<S> vec(5);
is well defined then why is:
std::vector<S> vec(5, S());
undefined behavior?
If we go to the cppreference section of std::vector::vector we can see in the first case it (since C++11) (emphasis mine):
Constructs the container with count default-inserted instances of T.
No copies are made.
while in the second case:
Constructs the container with count copies of elements with value
value.
The first case will default construct the elements and no copies are made while in the second case copies will be made and therefore we end up copying x
to each element. Since the default constructor of S
does not initialize x
, it will have an indeterminate value and therefore we have undefined behavior since producing an indeterminate value invokes undefined behavior.
Since C++14 section 8.5
paragraph 12
says:
If an indeterminate value is produced by an evaluation, the behavior
is undefined except in the following cases
with some exceptions in the case of unsigned char which does not apply in this case.
We know that x
has an indeterminate value from the same paragraph which says:
When storage for an object with automatic or dynamic storage duration
is obtained, the object has an indeterminate value, and if no
initialization is performed for the object, that object retains an
indeterminate value until that value is replaced
vec(5);` will default construct 5 separate instances (IIRC this change was made in C++11 to allow `vector` to contain move only types). If you subsequently cause copies of those to be made, then the same rules as explained above apply.– Praetorian Dec 30 '14 at 03:55