Boost logo

Boost :

Subject: Re: [boost] copy on write for std containers
From: Simonson, Lucanus J (lucanus.j.simonson_at_[hidden])
Date: 2010-12-04 19:49:16

Pierre Morcello wrote:
> Hi Luke,
> lucanus.j.simonson_at_[hidden] wrote:
>>>> "To return a container pass it by non-const reference and populate
>>>> it, which avoids copy on return."
> Certainly, but shouldn't we promote a little more copy elision
> instead ? This is supposed to avoid copy on return too, or did I
> misunderstood it?
> Best regards,
> Pierre
> PS: grats for the polygon lib!


>> Peter Foelsche wrote:
> One should also be cognizant of the optimization opportunities
> afforded
> you by the presence of Return Value Optimization (RVO) and move
> semantics (if available). These generally give one the same interface
> choices that copy-on-write would allow but without the overhead. For
> example, if your function does an unconditional copy-modify-return,
> you should pass by value and return by value; contemporary compilers
> elide
> the spurious copies.
> To specifically address returning a container: If I wanted to return a
> container, I think you want to prefer returning by value and relying
> on
> RVO and/or move assignment and/or swap. This simplifies the interface
> and makes the program's reasoning easier to parse. I would only
> modify
> an existing container in-place (i.e., take a reference to a
> to-be-modified container) if the semantics are explicitly to "add" to
> the container.
> Of course, rvalue references aren't available on every compiler yet.
> For those C++03 compilers, one could use the (proposed) Boost.Move
> library or, if that isn't an option, swap can sometimes be used as
> poor
> man's move assignment.

Peter and Pierre have some points about the direction C++ is taking from the old standard usage and the new. I actually like to have an accumulate semantic on containers I pass by reference most of the time. I know I should use an output iterator instead, mea-culpa. The other thing I like about pass by reference is it places memory management responsibility on the caller (which output iterators also do, of course). If the caller wants to allocate a std container on the heap or make it a data member of a class and pass it to a function by reference to populate it they can do so at no extra cost. Yes r-value references, NRVO, RVO and copy ellison/move semantics all help make those things zero-cost, but I take some comfort in writing code that I know for sure will compile to an efficient executable in every C++ compiler. Also, I don't find passing by const reference to be much of a cognitive overhead and I admit passing by reference to populate a container gets in the way of equational reasoning and forces multi-line syntax where a single expression might be more natural, but I like accumulate semantics and I like pushing ownership of containers down the call stack as far as possible and not trasfering that ownership around. Generally when passing containers around I like to make them template parameters. A return value type can't be an implicit template parameter, while calls to a template function with pass by reference can usually be made bare without supplying a template parameter list, which makes using them more intuitive. We can never infer the return type of a template function by what comes on the left hand side of the assignment operator. Well, I guess I do use expression templates with generic assignment operators to get my equational reasoning, infer the right hand side and still use pass by reference under the hood. It's a lot of work, but we have proto to help with that.

Getting the ownership of an object right in the first place seems to me to be 95% of the problem and a lot of these things like RVO and copy-ellison is there to address the 5%. I'd rather people learn how to manage the lifetime of their objects properly than learn the new language features. Once you have the 95% covered see how the new langauge features can help you with the remaining 5%. Build the pyramid from the bottom up.


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