Doubt in GotW #27 - forwarding functions

S

Srini

Hello all,

I was going thru the GotW archives where I had a doubt in this
particular item.

http://www.gotw.ca/gotw/027.htm

There is a mention about a subtle change to the standard in July 1997.
According to that, the only places a compiler can eliminate making copy
of objects is in case of return value optimization and temporary
objects. For a piece of code like -

bool g(X x) {
// ...
return true; // or false
}

bool f(X x) {
return g(x);
}

// user code
X xObj;
bool truth = f(xObj);

The compiler cannot optimize the code to construct the copy of 'xObj'
in function 'g' directly. It has to perform 2 copies - one from 'xObj'
of user code to 'x' of function 'f' and then another from 'x' of
funtion 'f' to 'x' of function 'g'. As to the reason for why this was
done, a note at the bottom of the page says -

"This change was necessary to avoid the problems that can come up when
compilers are permitted to wantonly elide copy construction, especially
when copy construction has side effects. There are cases where
reasonable code may rely on the number of copies actually made of an
object."

I'm not very clear about this reason. What kind of side-effects of copy
construction can lead to problems. An example would help me understand
this better. Also, if code relies on the actual number of copies made
of an object, would it not be affected by return value optimization?

Regards,
Srini
 
A

Alf P. Steinbach

* Srini:
Hello all,

I was going thru the GotW archives where I had a doubt in this
particular item.

http://www.gotw.ca/gotw/027.htm

There is a mention about a subtle change to the standard in July 1997.
According to that, the only places a compiler can eliminate making copy
of objects is in case of return value optimization and temporary
objects. For a piece of code like -

bool g(X x) {
// ...
return true; // or false
}

bool f(X x) {
return g(x);
}

// user code
X xObj;
bool truth = f(xObj);

The compiler cannot optimize the code to construct the copy of 'xObj'
in function 'g' directly. It has to perform 2 copies - one from 'xObj'
of user code to 'x' of function 'f' and then another from 'x' of
funtion 'f' to 'x' of function 'g'. As to the reason for why this was
done, a note at the bottom of the page says -

"This change was necessary to avoid the problems that can come up when
compilers are permitted to wantonly elide copy construction, especially
when copy construction has side effects. There are cases where
reasonable code may rely on the number of copies actually made of an
object."

I'm not very clear about this reason

Neither am I. ;-)

It would have been nice if the relevant paragraphs in the standard were
referred to.

What kind of side-effects of copy construction can lead to problems.

All kinds, so the question is rather what kind of side-effect of copy
construction does _not_ lead to problems, i.e. can be relied on.

And there I don't know any answer.

My guess would be that someone on the committee had a pet piece of "clever"
code, e.g. logging or some such, that would continue to work when elision of
copy construction for arguments was disallowed. An alternative guess is
that Herb had misunderstood. After all, he's only human.

An example would help me understand
this better. Also, if code relies on the actual number of copies made
of an object, would it not be affected by return value optimization?

One would think so.
 
F

Fraser Ross

"Srini"
this better. Also, if code relies on the actual number of copies made
of an object, would it not be affected by return value optimization?


The short lifetime of the object created for returning may be the reason for
allowing it to be optimised out.

Fraser.
 
S

Srini

I'm not very clear about this reason
Neither am I. ;-)

It would have been nice if the relevant paragraphs in the standard were
referred to.

Alf - thanks for your reply. I have a draft copy of the standard which
might be old. I referred to section 12.2 dealing with temporary
objects. I could not find anything relating to the behavior quoted in
GotW #27.
All kinds, so the question is rather what kind of side-effect of copy
construction does _not_ lead to problems, i.e. can be relied on.

And there I don't know any answer.

Now I understand that copy constructor with side-effects can cause
subtle problems.
My guess would be that someone on the committee had a pet piece of "clever"
code, e.g. logging or some such, that would continue to work when elision of
copy construction for arguments was disallowed. An alternative guess is
that Herb had misunderstood. After all, he's only human.

Are you of the opinion that this restriction on the compilers not to
optimize copies during calls to forwarding functions is unnecessary?
Even if, as you mentioned, someone on the committee had a clever piece
of code, do you think it makes sense to have this kind of a restriction
specified in the standard? I've been thinking about this, but, till
now, have not been able to properly reason this out.

Regards,
Srini
 
S

Srini

* Fraser Ross
The short lifetime of the object created for returning may be the reason for
allowing it to be optimised out.

Yeah - that could be the reason. Since its lifetime is short and it is
being returned, it can have utmost 1 copy of itself made.

Srini
 
H

Herb Sutter

Neither am I. ;-)

It would have been nice if the relevant paragraphs in the standard were
referred to.

Some people had code examples where they cared about the presence or
absence of side effects (I think one example was logging).
All kinds, so the question is rather what kind of side-effect of copy
construction does _not_ lead to problems, i.e. can be relied on.

Any side effect that the programmer cares about can lead to problems if
the compiler removes it. Of course, knowing which ones those are requires
reading the programmer's mind. :) For example, if the side effect is to
increment a global counter keeping track of how many times a certain thing
happened, then in some cases you don't care if it's not updated, but in
some cases you do care (e.g., if you're relying on the count for
instrumenting how many times a code path was taken).

The bottom line is that copy constructor elision changes the meaning of
the program, although in a way that's innocuous for all plain value types
(which many C++ types are) and for many more complex types. But whenever
you change the sequence of actions that the programmer wrote, you run the
risk that you might not be doing him a favor.
One would think so.

Yes, it would. But when the committee in 1997 restricted the freedom for
the compiler to elide copies, the RVO was explicitly and specially
excluded so that compilers could continue to elide copies of return
values. True, giving one case special treatment wasn't consistent, but
people weren't willing to give up the RVO largely because the RVO was
known to have important performance benefits in some scenarios, and the
scope for surprising programmers by eliding copies of return values in
particular seemed to be less.

Note that probably all of this could have been regularized if the language
had had move constructors, which presumably could be applied to RVO-style
cases. Howard Hinnant is now proposing move construction/assignment for
C++0x and so far is getting a warm reception by the committee. Google for
"wg21 hinnant move constructor" for more details on this interesting
topic.

Herb

---
Herb Sutter (www.gotw.ca) (www.pluralsight.com/blogs/hsutter)

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top