By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
457,733 Members | 924 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 457,733 IT Pros & Developers. It's quick & easy.

Question on C++ book example

P: n/a
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

Jul 15 '06 #1
Share this Question
Share on Google+
3 Replies


P: n/a
<xl***************@gmail.comwrote:
I have a question about an example presented in the book "INFORMIT C++
Reference Guide" by Danny Kalev:

string getmagicword()
(
return string("Supercalifragilisticexpialidocious");
);
Ummm, no. Perhaps what you mean is:

std::string getmagicword()
{
return string("Supercalifragilisticexpialidocious");
}

Dumb function, though. I'd do this instead:

#define MAGIC_WORD std::string("Supercalifragilisticexpialidocious")

or perhaps this:

const std::string magic_word ("Supercalifragilisticexpialidocious");

Either way saves time and reduces stack usage during runtime.
string magicw=getmagicword();

"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.
I think it's likely a good compiler would elide some of those
constructor calls. But keep in mind that you ARE using copy
semantics here. If you don't want copies, don't use copy
semantics; pass by ref instead. (More on this below.)
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:

void getmagicword(string object)
(
);
Huh? Do you mean:

void getmagicword(string object)
{
object = std::string("Bob");
}

If so, that won't work. You're still using copy semantics.
Altering object won't alter the argument.

int main()
{
std::string x = "Fred";
getmagicword(x); // Does NOTHING.
std::cout << x << std::endl; // prints "Fred", not "Bob".
return 0;
}
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?*/
Something close to that, yes. Maybe fewer constructor calls than
you think. Others here could give you more technical details.
Dumb way to go about it, in any case.
/* 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? */
No. Second example doesn't alter argument at all. (See above.)
If this is different from returning an object
You're not returning an object. Return is "void", remember?
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
When passing by value, altering a parameter does not alter its
argument. (See above.)
(without optimizations of course)?
Optimization has nothing to do with it.

If you need to pass a string into a function which will alter
it, pass the argument by non-constant reference, like this:

void LoadString (std::string & Text)
{
Text = std::string("Bob");
}

int main()
{
std::string Fizzbin ("Fred"); // Loads "Fred" into Fizzbin
LoadString(Fizzbin); // loads "Bob" into Fizzbin
std::cout << Fizzbin << std::endl; // prints "Bob", not "Fred"
return 0;
}

To pass a string (or anything else) to a function that WON'T
alter it, pass the argument by constant reference to reduce
time and RAM wasted making unnecessary copies of things:

double MyQuad(double const & num) // num is alias for argument
{
// Note: num is NOT a local variable here! It's an alias
// to the argument passed to MyQuad. In the case of
// the function call in main() below, num is an alias to
// the variable Tom.
return 3.87*num*num - 17.3*num + 4.57; // return quadratic
}

int main()
{
double Tom = 18.2;
std::cout << MyQuad(Tom) << std::endl; // print quadratic
return 0;
}

(In practice, I'd use a functor for MyQuad, passing-in the
coefficients by parameterized constructor... but I digress.)
--
Cheers,
Robbie Hatley
East Tustin, CA, USA
lone wolf intj at pac bell dot net
(put "[usenet]" in subject to bypass spam filter)
http://home.pacbell.net/earnur/
Jul 15 '06 #2

P: n/a
xl***************@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
Jul 15 '06 #3

P: n/a
xl***************@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");
);
Should be (if you want it to compile!)

std::string getmagicword()
{
return std::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."
In a naive or unoptimised version, yes. Any decent compiler would
optimise away the call to getmagicword() and create magicw in place with
the string literal "Supercalifragilisticexpialidocious".
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)
(
);
Should be (if you want it to compile!)

void getmagicword( std::string& s )
{
s = "Supercalifragilisticexpialidocious";
}
string x;
getmagicword(x); // first example
getmagicword(string()); second example
Again, the call to getmagicword(x) can be optimised away in the same way
as the previous example.

--
Ian Collins.
Jul 15 '06 #4

This discussion thread is closed

Replies have been disabled for this discussion.