Boost logo

Boost :

Subject: Re: [boost] rvalue ref best practices?
From: Dave Abrahams (dave_at_[hidden])
Date: 2012-06-15 00:39:01

on Tue Jun 12 2012, "Simonson, Lucanus J" <> wrote:

> Dave Abrahams wrote:
>>> If you aren't in a loop you probably don't care about performance. I
>>> know I intend to stick with pass by reference. It is very useful to
>>> clearly understand and be able to easily reason about the ownership of
>>> resources in a program.
>>If that's your primary concern, why on earth wouldn't you use pass-by-value?
> Let's take a sort of extreme example:
> A a;
> mutate(a, b); //a passed by reference as in/out
> mutate(a, c);
> vs.
> A a;
> a = mutate_rvr(std::move(a), b);
> a = mutate_rvr(std::move(a), c);
> Here I compare an accumulate semantic with and without move semantics.
> Both make zero copies. The latter results in four moves of a while
> the former has zero moves of a.

But that's not your primary concern.

> The former is less readable because you need to know that the first
> argument is the output. In my coding convention such functions are
> always named with a verb describing the action taken on the in/out
> parameter and the in/out is the first argument. A function that
> returns by value is named with a noun describing the return value. By
> convention I always know what is going on when I pass by reference for
> in/out parameters. The second allows equational reasoning, but
> composes the same since mutate returns a reference to A, again by my
> personal convention.

But it doesn't guarantee no aliasing. a and b could turn out to be the
same object, which means they share ownership of... whatever it is they

> mutate(mutate(a,b),c);
> a = mutate_rvr(mutate_rvr(std::move(a), b),c);
> I just don't find it easier to think about an interface that requires
> that I transfer ownership of an object into it so that it can modify
> the object then return it by value to transfer ownership back.

That's the "wrong" way to think about it. You're not transferring
ownership; you're computing new values. Even the names you use muddle
this distinction. "mutate_rvr" says it's a logical mutation, when it
isn't. It's a noun, like you said. So:

     const X d = compute(compute(a, b), c);

is what you should start with, from the "thinking about it" point of
view. Then you might do things like these

     a = compute(compute(move(a), b), c);
     ^ ^^^^^^^

as optimizations.

> The reason I don't find it easier is because it is unnecessary and
> error prone. It is very easy to forget to call move.

Then performance is your concern, not eliminating the need to think
about ownership.

> A a;
> a = mutate_rvr(a, b);
> a = mutate_rvr(a, c);
> It will compile, function correctly passing tests, but it is now a
> performance bug.


    A a;
    a = compute(a, b);
    a = compute(a, c);

It would be nice if the compiler could insert those moves for us,
wouldn't it?

> To catch these bugs I need to put a logger in the
> copy constructor/assignment operator and run a special test to audit
> move/copy behavior. (or make A a move only type, which seems
> draconian)
> I also find copy Ellison and RVO harder to reason about than reference
> semantics because it is more complex and less explicit in the code to
> figure out whether the optimizations will be applied.
> I would rather use std::move in the special cases where I no longer
> should have ownership of an object in the current scope because the
> design intent is to transfer that ownership somewhere else (into a
> container, for example).

You know, I don't think of move in terms of ownership transfer unless
unique_ptr is involved.

> These are the places I am returning/passing by value in C++03. I
> don't know where to draw the line in changing coding style to make use
> of move semantics, but I don't think it should be drawn at either
> extreme, and I see very little downside to drawing it closer to the
> C++03 style that already works very well for me.

+1. Definitely do what works for you.

> There is no doubt that I would use move semantics everywhere that
> transfer of ownership is necessary and the performance advantage of
> move versus copy is beneficial. Everywhere else I'm inclined to
> continue to use references or make copies. We can do three things.
> We can copy, we can refer-to and we can transfer-ownership-of. There
> is plenty of occasion to need to do all three when programming. I
> would think that we should all just do whichever best fits our design
> intent in any given situation rather than try to prefer one over
> another.

I hate to say this, because I agree with what you've said,
but... "obviously." I get the sense you're arguing with the position of
someone who isn't around this list at the moment.

Dave Abrahams
BoostPro Computing

Boost list run by bdawes at, gregod at, cpdaniel at, john at