473,386 Members | 1,654 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,386 software developers and data experts.

Question on C++ book example

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
3 1769
<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
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
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

15
by: Wolfram Humann | last post by:
Hi, please don't be too harsh if I made stupid errors creating this simple example from my more complex case. Suppose I have a class like this: class BOOK { const string title;
7
by: artifact | last post by:
Can anyone tell me how to access a variable in a parent class from within a nested class? Note: this snippet is only to illustrate my problem... I realize there's no need to get at the parent name...
1
by: Tony Johansson | last post by:
Hello! I'm reading a book about C++ and there is something that I don't understand so I ask you. I have marked the section from the book that is of intertest by tagging it with BOOK START HERE...
7
by: Ot | last post by:
I posted this to the wrong group. It went to m.p.dotnet.languages.vb. Ooops. -------------------------------------------------------------------- I have this tiny problem. I have learned...
15
by: designconcepts | last post by:
bo'jour, bo'jour, So I have question to present to the forum about OOD. This is a Csharp forum, but C# is the lang of choice and the question is an exercise based on some comments by the chief...
3
by: John Salerno | last post by:
Along with events and delegates, polymorphism has been something I sort of struggle with every now and then. First, let me quote the book I'm reading: "Polymorphism is most useful when you have...
9
by: me | last post by:
Hi All, I am new to Classes and learniing the ropes with VB.NET express Here's my question - say I have a want to manage a list of books. Each book has an Author, Title and ISBN Now, I am...
2
by: djc | last post by:
I read a network programming book (based on framework 1.1) which indicated that you should 'never' use the RecieveTimeout or the SendTimeout 'socket options' on TCP sockets or you may loose data. I...
11
by: proctor | last post by:
hello, i have a regex: rx_test = re.compile('/x()*x/') which is part of this test program: ============ import re
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.