Difference between `vector<int> v;` and `vector<int> v = vector<int>();`
Starting from C++17 there's no difference whatsoever.
There's one niche use case where the std::vector = std::vector
initialization syntax is quite useful (albeit not for default construction): when one wants to supply a "count, value" initializer for std::vector<int>
member of a class directly in the class's definition:
struct S {
std::vector<int> v; // Want to supply `(5, 42)` initializer here. How?
};
In-class initializers support only =
or {}
syntax, meaning that we cannot just say
struct S {
std::vector<int> v(5, 42); // Error
};
If we use
struct S {
std::vector<int> v{ 5, 42 }; // or = { 5, 42 }
};
the compiler will interpret it as a list of values instead of "count, value" pair, which is not what we want.
So, one proper way to do it is
struct S {
std::vector<int> v = std::vector(5, 42);
};
The 1st one is default initialization, the 2nd one is copy initialization; The effect is same here, i.e. initialize the object v
via the default constructor of std::vector
.
For std::vector<int> v = std::vector<int>();
, in concept it will construct a temporary std::vector
then use it to move-construct the object v
(note there's no assignment here). According to the copy elision (since C++17 it's guaranteed), it'll just call the default constructor to initialize v
directly.
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible, as the language rules ensure that no copy/move operation takes place, even conceptually:
In the initialization of a variable, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:
T x = T(T(f())); // only one call to default constructor of T, to initialize x
(Before C++17, the copy elision is an optimization.)
this is an optimization: even when it takes place and the copy/move (since C++11) constructor is not called, it still must be present and accessible (as if no optimization happened at all),
BTW: For both cases, no std::vector
objects (including potential temporary) will be constructed with dynamic storage duration via new
expression.