Saturday, October 31, 2009

Solution




I l@ve RuBoard









Solution




1. What is the difference between direct initialization and copy initialization?



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" equivocation 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, in addition, take or return an object rather than a reference. Also, the copy and conversion constructors could have additional default arguments.


Note that in the last case ("T t3 = u;") the compiler could call both the user-defined conversion (to create a temporary object) and the T copy constructor (to construct t3 from the temporary), or it could choose to elide the temporary and construct t3 directly from u (which would end up being equivalent to "T t3(u);"). Either way, the unoptimized code must still be legal. In particular, the copy constructor must still be accessible, even if the call to it is optimized away.


In the C++ standard, the compiler's latitude to elide temporary objects has been restricted compared with the latitude compilers enjoyed in pre-standard times. Elision is still allowed, however, for this optimization and for the return value optimization. For more details, see Exceptional C++ [Sutter00] Item 42 about the basics, and Exceptional C++ Item 46 covering the change in the final standard.


Guideline





Prefer using the form "T t(u)" over "T t = u" for variable initialization.






2. Which of the following cases uses direct initialization, and which uses copy initialization?



In the standard, the thrilling section 8.5 covers most of these. There were also three tricks that don't involve initialization at all. Did you catch them?



class T : public S
{
public:
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<S&>(t); // performing a reinterpret_cast
dynamic_cast<T&>(r); // performing a dynamic_cast
const_cast<const T&>(t); // performing a const_cast

Trick: No initialization of a new object is involved in these cases. Only references are created.



static_cast<S>(t); // performing a static_cast

A static_cast uses direct initialization.



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.


In general, though, prefer to catch exceptions by reference, not by value, to avoid making extra copies and to eliminate potential object slicing.[1]


[1] See also Item 13 in [Meyers96].



f( T(s) ); // functional-notation type conversion

This function-style cast 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

Finally, new expressions use direct initialization.








    I l@ve RuBoard



    No comments:

    Post a Comment