Re: Question on C++ book example
xllx.relient.xllx@gmail.com wrote:
I have a question about an example presented in the book "INFORMIT C++
Reference Guide" by Danny Kalev:
<code>
string getmagicword()
(
return string("Supercalifragilisticexpialidocious");
);
string magicw=getmagicword();
</code>
"getmagicword() constructs a local string object. Next, this local
object is copy-constructed on the caller's stack, making a temporary
string object that is used as the argument of magicw's assignment
operator/copy-constructor. Next, magicw's copy constructor executes, at
last.
Yes, you heard me right: to initialize magicw, it takes no less than:
One constructor call for the local object inside getmagicword().
Two copy constructor calls: one for copying the local object onto the
caller's stack frame, and then another call for copying that copy to
magicw.
Two destructor calls: one for the object created inside getmagicword
and one for the temp copied onto the caller's stack frame."
Now, my question is: Would the same thing happen (a temporary being
created) if you passed an object to the function:
<code>
void getmagicword(string object)
(
);
string x;
getmagicword(x); // first example
getmagicword(string()); second example
/* In applying the same principal that the book showed for returning
objects, I came up with the following for passing objects to functions:
*/
/* first example calls constructor, then creates temporary object (out
of local object) on the caller's stack which calls the copy
constructor, then it calls the copy constructor again to initialize the
functions argument with the temporary - Yes?*/
/* second example calls constructor, that creates and returns a
temporary object, then calls the copy constructor to create another
temporary object on the caller's stack and initializes it with the
first temporary object, then it calls the copy constructor again to
initialize the functions argument with the last temporary object. -
Yes? */
</code>
If this is different from returning an object in that a temporary is
not created, then why the double standard? How is the passed in object
initialized to the actual argument in the function definition (without
optimizations of course)?
Thanks
Question. Suppose we have some function defined as follows:
void f (T& inOut)
{
// do something to inOut
<-- what happens if we get an exception here?
// do another thing to inOut
}
What state is inOut in when the exception is thrown? Even if we
surrounded the operations in a try block
try
{
// operations modifying inOut that might throw
}
catch (Eclass& e)
{
// what can we do in here to roll-back modifications to inOut?
}
could we guarantee roll-back of the modifications to inOut without
having saved its state first?
Contrast this with a sequence like the following:
try
{
// copy inOut (heap copy naturally) <-- this might throw
// do something with the copy <-- as might this
// swap the copy and inOut <-- this can't throw
}
catch (Eclass& e)
{
// can we guarantee roll-back here?
}
This is a paraphrase of (one of) Herb Sutter's exception safety missives.
Why, then are we so concerned with copying a value in the return
statement when that is probably safer than directly modifying the
aliased object? Fine if the modifications can't throw but can we
guarantee that in general?
Another concern is thread safety. Can we guarantee that the operations
on the reference are atomic? Would copying be better under these
circumstances? (I genuinely don't know BTW).
We also might want to use copy if we're doing Design by Contract, say
something like this:
void f (T& inOut)
{
// Check preconditions -> throw if invalid
// Copy inOut
// Modify copy
// Check postconditions -> throw if invalid
// non-throwing swap of copy and inOut
}
If we get past checking the postconditions (assuming they are correct
according to the specification) then if conditions are violated on exit
we know the bug is in the (allegedly) non-throwing swap.
Rather than saying copying has to be avoided, say rather that it can be
avoided if it is safe to do so, otherwise copying may be necessary for
safety or other reasons.
The example in the article is not meant to be production code but merely
an illustration of how a return statement works with copy semantics.
There are better examples in other books, say "Accelerated C++" and "You
Can Program in C++", and not forgetting "The C++ Programming Language",
so perhaps the author should have used one of these.
Cheers
Jim