For primitive types both are equivalent, it is for user defined class types that there is a difference. In both cases the code that gets executed will be the same (after basic optimizations are performed), but the requirements on the types differ if the element from which we are initializing is not of the type that we are constructing.
The copy-initialization (T t = u;
) is equivalent to copy construction from a temporary of type T
that has been implicitly converted from u
to t
. On the other hand direct-initialization is equivalent to a direct call to the appropriate constructor.
While in most circumstances there will be no difference, if the constructor that takes the u
is declared explicit
or if the copy-constructor is inaccessible, then copy-initialization will fail:
struct A {
explicit A( int ) {}
};
struct B {
B( int ) {}
private:
B( B const & );
};
int main() {
A a(1); // ok
B b(1); // ok
// A a2 = 1; // error: cannot convert from int to A
// B b2 = 1; // error: B( B const & ) is not accessible
}
For some historical background, initially primitive types had to be initialized with copy-initialization. When *initializer-list*s were added to the language to initialize member attributes from a class, it was decided that primitive types should be initialized with the same syntax that classes to keep the syntax in the initializer list uniform and simple. At the same time allowing the initialization of classes by means of copy-initialization makes user defined types closer to primitive types. The differences in the two initialization formats comes naturally: int a = 5.0;
is processed as a conversion from 5.0
to int
, and then initialization of a
from the int
. The same goes with user defined types: T u = v;
is processed as conversion from v
to T
, and then copy construction of u
from that converted value.