Until as recently as 1997, the draft C++ language standard said that because a compiler can prove that the parameter x will never be used for any other purpose than passing it in turn to
Trang 1Remember the introduction to the question? It was: Forwarding functions are useful tools for handing off work to another
function or object, especially when the hand-off is done
efficiently
This introduction gets to the heart of the matter—efficiency
There are two main enhancements that would make this
function more efficient The first should always be done; the second is a matter of judgment
1 Pass the parameter by const& instead of by value.
"Isn't that blindingly obvious?" you might ask No, it isn't, not in this particular case Until as recently as
1997, the draft C++ language standard said that
because a compiler can prove that the parameter x
will never be used for any other purpose than passing
it in turn to g(), the compiler may decide to elide x
completely (that is, to eliminate x as unnecessary) For example, if the client code looks something like this:
X my_x;
f( my_x );
then the compiler used to be allowed to either:
Create a copy of my_x for f()'s use (this is the parameter named x in f()'s scope) and pass that
to g()
Trang 2at all, because it notices that the extra copy will never be used except as a parameter to g()
The latter is nicely efficient, isn't it? That's what optimizing compilers are for, aren't they?
Yes and yes, until the London meeting in July
1997 At that meeting, the draft was amended to place more restrictions on the situations in which the compiler is allowed to elide "extra" copies like this This change was necessary to avoid
problems that can come up when compilers are permitted to wantonly elide copy construction, especially when copy construction has side
effects There are reasonable cases in which
reasonable code may legitimately rely on the
number of copies actually made of an object.
Today, the only situation in which a compiler may still elide copy constructors is for the return value optimization (see your favorite textbook for
details) and for temporary objects This means that for forwarding functions like f(), a compiler
is now required to perform two copies Because
we (as the authors of f()) know in this case that the extra copy isn't necessary, we should fall back
on our general rule and declare x as a const X&
parameter.
Guideline
Prefer passing objects by reference instead of by value, using const
wherever possible.
Trang 3Note: If we'd been following this general rule all along instead of trying to take advantage of
detailed knowledge about what the compiler is allowed to do, the change in the rules wouldn't have affected us This is a stellar example of why simpler is better—avoid the dusty corners of the language as much as you can, and strive never to rely on cute subtleties.
Guideline
Avoid the "dusty corners" of a language; use the simplest techniques that are effective.
Inline the function This one is a matter of judgment In
short, prefer to write all functions out-of-line by default, and then selectively inline individual functions as necessary only after you know that the performance gain from inlining is
actually needed
Guideline
Avoid inlining or detailed tuning until performance profiles prove the need.
Trang 4If you inline the function, the positive side is that you avoid the overhead of the extra function call to f()
The negative side is that inlining f() exposes f()'s
implementation and makes client code depend on it so that if
f() changes, all client code must recompile Worse, client code now also needs at least the prototype for function g(), which is
a bit of a shame because client code never actually calls g()
directly and probably never needed g()'s prototype before (at least, not as far as we can tell from our example) And if g()
itself were changed to take other parameters of still other
types, client code would now depend on those classes'
declarations, too
Both inlining and not inlining can be valid choices It's a
judgment call in which the benefits and drawbacks depend on what you know about how (and how widely) f() is used today, and how (and how often) it's likely to change in the future