Re: What's the point of passing parameter by value (vs. const ref)
on Mon Jul 07 2008, LR <lruss-AT-superlink.net> wrote:
David Abrahams wrote:
Your original code follows. Somehow it's not getting quoted in the
reply. So I put it in by hand.
{ Our apologies. Somehow an article with attachments (even if only pure text)
slipped through both moderation and our posting software. -mod/aps }
Mods: are you saying that my article should have been rejected because
of the inline text attachments? I'm not sure that's a great policy,
since inline plaintext is the only way to get some newsreaders not to
wrap lines, which tends to obfuscate the code.
#include <utility>
#include <iostream>
struct trace
{
trace() { std::cout << "default ctor\n"; }
trace( trace const& ) { std::cout << "copy ctor\n"; }
trace& operator=( trace const& ) {
std::cout << "copy assign\n"; return *this; }
How is that implemented? Perhaps
trace &operator-(const trace &t) {
std::cout << "assign" << std::endl;
trace temp(t); // one copy ctor
swap(temp); // void trace::swap(trace &); not shown
return *this;
}
Not if you want it to be efficient with rvalues. Instead:
trace& operator=(trace rhs) { swap(*this,rhs); return *this; }
~trace() { std::cout << "dtor\n"; }
friend void swap( trace& x, trace& y ) { std::cout << "swap\n"; }
};
<schnipp>
------------------------------------------------------------------------
--------------------------------------------------------------------------
After I run this code with the changes I described, and a few other
minor ones, I get this output:
default ctor
=== by reference ===
default ctor
assign
copy ctor
trace::swap(trace &t)
dtor
dtor
=== by value ===
default ctor
copy ctor
assign
copy ctor
trace::swap(trace &t)
dtor
assign
copy ctor
trace::swap(trace &t)
dtor
dtor
dtor
=== done ===
dtor
What conclusions can we draw from that?
Your compiler seems to be doing some nice optimizations for the value
version.
The output from your by value version is,
=== by value ===
default ctor
swap
dtor
=== done ===
I'm a little curious as to what's happening to the instance of trace()
that you're passing to set_by_value.
It's an allowed optimization called "copy elision." Most modern
compilers do it (probably yours, even). The compiler is allowed to
eliminate any copying of an rvalue passed as a by-value argument and any
copying performed when returning by value from a function. Both
optimizations are done by allocating the storage for the argument/return
value in the caller's stack area.
I wonder what would happen if the code was a little different, maybe,
m("=== by value ===");
const trace t;
h.set_by_value( t );
// do something else with t here
Now the argument is an lvalue; the compiler is forced to copy it.
--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]