TITLE: direct and copy initialization (Newsgroups: comp.lang.c++.moderated, 15 Jun 98) AUTHOR: herbs@cntc.com (Herb Sutter) .--------------------------------------------------------------------. | Guru of the Week problems and solutions are posted regularly on | | news:comp.lang.c++.moderated. For past problems and solutions | | see the GotW archive at http://www.cntc.com. | | Is there a topic you'd like to see covered? mailto:herbs@cntc.com | `--------------------------------------------------------------------' _______________________________________________________ GotW #36: Copies Difficulty: 5 / 10 _______________________________________________________ >Guru JG Question >---------------- > >What is the difference between "direct initialization" >and "copy initialization"? > >(Hint: See an earlier GotW.) Direct initialization means the object is initialized using a single (possibly conversion) constructor, and is equivalent to the form "T t(u);": U u; T t1(u); // calls T::T( U& ) or similar Copy initialization means the object is initialized using the copy constructor, after first calling a user-defined conversion if necessary, and is equivalent to the form "T t = u;": T t2 = t1; // same type: calls T::T( T& ) or similar T t3 = u; // different type: calls T::T( T(u) ) // or T::T( u.operator T() ) or similar [Aside: The reason for the "or similar"s above is that the copy and conversion constructors could take something slightly different from a plain reference (the reference could be const or volatile or both), and the user-defined conversion constructor or operator could additionally take or return an object rather than a reference.] UPDATE: In the last case ("T t3 = u;") the user-defined conversion and the T copy constructor must both be called. In CD2 and until the London meeting in July 1997, the compiler was permitted to elide the copy constructor call as long as the copy constructor could have been called (i.e., was accessible). Since July 1997 and in the final draft standard, the compiler may not make this optimization to elide the copy constructor call. For more details, see GotW #1 (about the basics) and GotW #27 (about the 1997 change). >Guru Question >------------- > >Which of the following cases use direct initialization, >and which use copy initialization? Section 8.5 [dcl.init] covers most of these. There were also three tricks that actually don't involve initialization at all... did you catch them? > struct T : S { > T() : S(1), // base initialization > x(2) {} // member initialization > X x; > }; Base and member initialization both use direct initialization. > T f( T t ) { // passing a function argument > return t; // returning a value > } Passing and returning values both use copy initialization. > S s; > T t; > S& r = t; > reinterpret_cast(t); // performing a reinterpret_cast Trick: A reinterpret_cast does no initialization of a new object at all, but just causes t's bits to be reinterpreted (in-place) as an S. > static_cast(t); // performing a static_cast A static_cast uses direct initialization. > dynamic_cast(r); // performing a dynamic_cast > const_cast(t); // performing a const_cast More tricks: No initialization of a new object is involved in either of these cases. > try { > throw T(); // throwing an exception > } catch( T t ) { // handling an exception > } Throwing and catching an exception object both use copy initialization. Note that in this particular code there are two copies, for a total of three T objects: A copy of the thrown object is made at the throw site, and in this case a second copy is made because the handler catches the thrown object by value. > f( T(s) ); // functional-notation type conversion "Constructor syntax" type conversion uses direct initialization. > S a[3] = { 1, 2, 3 }; // brace-enclosed initializers Brace-enclosed initializers use copy initialization. > S* p = new S(4); // new expression New expressions use direct initialization.