- [Jon] So I want to share something I do
in my other job which is training,
I'm gonna show you slides
based on some work by Dave Abrahams.
He showed me this, what
I'm about to show you,
on copy elision and
return value optimization.
And it totally opened my eyes about that,
because I knew what those were,
but I was always a little dubious.
Like, how do I know the
compiler can really do that?
I was, "Yeah okay, people talk about it."
And I just didn't believe it.
So, he showed how it works
which I'm about to show you in a minute,
and I was astounded, it's like,
"That makes so much
sense, and now I get it!"
And so I'm gonna show it to you,
and I hope you appreciate it,
but Dave wasn't that happy.
I said, "These are just amazing!"
And he said, "No they're
not really right."
And I say, "What, these are great?"
And he says, "They're not so great."
"What are you talking about?"
I learned something from this
that I will remember forever,
and he said, "Well yeah but technically
they're not correct
because of this and this."
So I said, "Well fine, I fixed them."
So this is my fixed version,
but all the credit goes to Dave,
the real work is Dave's,
really an inspiration.
So copy elision is based on
the fact that the compiler
is allowed to follow the as if rule,
which is the compiler is
allowed to generate any code
that has the same effect as
the code you told it to write.
(indistinct) all sorts of things,
but there's an addition in the standard.
The standard actually says
that if the compiler is told
to copy something, but the
copy is not really necessary
because the original isn't
going to be used again,
the compiler is allowed
to elide that copy.
And you can tell if they've done that
if your copy constructor has side effects.
And the standard specifically says
that your side effects won't happen.
The compiler is allowed to elide those.
But now I'm gonna show you
how and why this happens.
The first thing I want to
ask you though is this,
this function F, how many
parameters does it take?
Okay so some people here
are C++ programmers,
and they're all saying zero.
And some people are assembly
language programmers
and they're all saying one.
The C++ programmers say none,
but assembly language
programmers say one, why?
What is the return value?
At the low level when
we have a return value
we have to tell the generated code
where to put the return value.
So that the function is
passing that address.
All right, so this is what's going on,
our function G is gonna
call our function F
in order to populate a local.
So here's our stack frame for
G, no parameters passed in,
but it has a local X,
now we're gonna call F,
and when we call F we're gonna have to
create the stack frame for
F, which has a parameter.
What's the parameter?
The address to the return value,
which in this case is?
The address of X, right?
Okay, now we execute F
and so we create our A
value and our B value,
and now we do the return,
and of course the return's gonna copy A
into the address where it's copied.
Does everybody see how that happens?
Does that make sense?
And this is how your
code is written if your
compiler engineer is a
complete and total moron.
But your compiler engineer is not
a complete and total moron.
What's the problem with this?
You've created something only
to turn around and copy it.
So that's not how this
is actually gonna work.
How is this actually gonna work?
What's gonna happen is
this, when we call F
we're gonna create the stack frame from F
which isn't going to have any place for A.
Why?
Because we're gonna create
A where it's eventually
supposed to be copied
to, but we're going to
elide the copy, right?
So this is the return value optimization.
So, in this situation here, G can we use
the return value optimization here?
No. Why?
Because the whole point of
the return value optimization
is that the compiler creates
the object to be returned
in the place where it's
going to be returned.
The compiler can only do
that if it knows which object
will be returned, and at
compile time you can't
know which object is going to be returned,
only at run time can it know.
So this is another situation
just slightly different.
Okay, so this can also work
on parameters passed in,
so in this case we're
passing in a temporary to F,
and so when we create the temporary there,
and then we call, call F and
pass it into the stack for F.
And again, this is how
your code will be written
if your compiler engineer
was a moron, which he's not,
or she is not, excuse me.
So this is how it actually works.
We are going to create our temporary
in the place where we would've copied it.
The compiler has to create a
temporary, it does it here.
Now of course as you
noticed this would not work
with an L value, this
works only for temporaries.
But in the case of
temporaries we can actually
completely avoid the copy by
simply doing this in place.
I hope that it gives
you some idea about how
this copy elision is actually
implemented at the low level,
and I will say that for me personally
understanding that made all the difference
in understanding RVO and copy elision.
Thank you very much.
(applause)
