What's the difference between
T a(b);
and
T a = b;
and
T a = T(b);
?
The main difference between these two types of initialization is that the copy initialization creates a separate memory block for the new object. But the direct initialization does not make new memory space. It uses reference variable to point to the previous memory block.
Copy initialization is performed in the following situations: 1) when a named variable (automatic, static, or thread-local) of a non-reference type T is declared with the initializer consisting of an equals sign followed by an expression.
Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.
T a( b );
is direct initialization, unless it parses as a function declaration, in which case it's a function declaration.
T a = b;
is copy initialization, which means that it works as if a temporary object is constructed on the right hand side, and that a
is then copy constructed or, in C++11 and later, possibly move constructed, from that temporary.
The compiler is free to elide (remove) the temporary+copying/moving whenever it can, but a copy or move constructor, whichever would be logically used, must still be accessible and not explicit
.
For example, in C++03 you cannot copy-initialize a std::ostringstream
, because it doesn't have a copy constructor. In C++11 you can copy-initialize an ostringstream
if the initializer is a temporary, which then results in a logical move construction (which however will usually be elided, optimized away). For example, this copy initialization declaration,
ostringstream s = ostringstream( "blah" );
… doesn't compile as C++03, because in C++03 the copy initialization invokes the class' copy constructor, which doesn't exist. It does however compile as C++11, because in C++11 the copy initialization invokes the move constructor. And while (to maintain its illusion of being a stream) a std::ostringstream
can't be directly copied, it can be moved.
Another such difference: in C++03 only the copy initialization syntax supports curly braces initializer, which in C++03 you can use when T
is an aggregate type such as a raw array. In C++11 the curly braces notation has been extended and generalized as a uniform initialization syntax, so it can be used also with direct initialization. And so the following direct initialization declaration,
int v[]{ 3, 1, 4, 1, 5, 9, 2, 6, 5, 4 };
… does not compile as C++03, but does compile as C++11 and later.
The =
copy initialization syntax is the original initialization syntax from C.
And in C++11 and later, due to move semantics, it can be used in a much wider range of cases than in C++03, such as with a std::ostringstream
.
T a(b);
Calls a constructor of a
that accepts b
. (If b
is of the same type, then the copy constructor is called).
T a = b;
a temporary object of type T
is created to be constructed by b
. Then the copy constructor is called(=
is not an assignment in this case and the next case!).
T a = T(b);
Same as above! except that we explicitly constructed a temporary object.
Note that the standard allows total elimination of temporary copies in the second and third case. Also, if b
is not of type T
, then in the first case T
doesn't have to have a copy constructor. In the second and third cases, even though the implementation is free to optimize the whole thing, it still requires an accessible copy constructor. IIRC the standard calls this: copy elision.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With