Solution
This puzzle demonstrates the difference between
three kinds of initialization: default initialization, direct
initialization, and copy initialization. It also contains one red
herring that isn't initialization at all. Let's consider the cases
one by one.
T t;
This is default
initialization. This code declares a variable named
t, of type T, which is initialized using the
default constructor T::T().
T t();
A red herring. At first glance, it may look like
just another variable declaration. In reality, it's a function
declaration for a function named t that takes no
parameters and returns a T object by value. (If you can't
see this at first, consider that the above code is no different
from writing something like int f(); which is clearly a
function declaration.)
Some people suggest writing "auto T
t();" in an attempt to use the auto storage class to
show that, yes, they really want a default-constructed variable
named t of type T. Allow me license for a small
rant here. For one thing, that won't work on a standard-conforming
compiler; the compiler will still parse it as a function
declaration, and then reject it because you can't specify an
auto storage class for a return value. For another thing,
even if it did work, it would be wrong-headed, because there's
already a simpler way to do what's wanted. If you want a
default-constructed variable t of type T, then
just write "T t;" and quit trying to confuse the poor
maintenance programmers with unnecessary subtlety. Always prefer
simple solutions to cute solutions. Never write code that's any
more subtle than necessary.
T t(u);
Assuming u is not the name of a type,
this is direct initialization. The
variable t is initialized directly from the value of u by
calling T::T(u). (If u is a type name, this is a
declaration even if there is also a variable named u in
scope; see above.)
T t = u;
This is copy
initialization. The variable t is always
initialized using T's copy constructor, possibly after
calling another function.
Common Mistake
|
This is always
initialization; it is never assignment, and so it never calls
T::operator=(). Yes, I know there's an "="
character in there, but don't let that throw you. That's just a
syntax holdover from C, not an assignment operation.
|
Here are the semantics:
-
If u is of type T, this is the
same as writing "T t(u);" and just calls T's copy
constructor.
-
If u is of some other type, then this
has the meaning "T t( T(u) );"—that is, u is
first converted to a temporary T object, and then
t is copy-constructed from that. Note, however, that in
this case the compiler is allowed to optimize away the "extra" copy
and convert it to the direct-initialization form (that is, make it
the same as "T t(u);"). If your compiler does this, the
copy constructor must still be accessible. But if the copy
constructor has side effects, then you may not get the results you
expect, because the copy constructor's side effects may or may not
happen, depending on whether the compiler performs the optimization
or not.
Guideline
|
Prefer using the form
"T t(u);" instead of "T t = u;" where possible.
The former usually works wherever the latter works, and has other
advantages—for example, it can take multiple parameters.
|
|