Boost logo

Boost :

Subject: Re: [boost] rvalue ref best practices?
From: Ion Gaztañaga (igaztanaga_at_[hidden])
Date: 2012-06-11 15:21:39


El 11/06/2012 13:02, Mathias Gaunard escribió:
> On 10/06/2012 22:38, Ion Gaztañaga wrote:
>
>> When thinking in solutions to this pass by value/reference issues, I
>> feel C++ is missing some language feature so that a function can detect
>> (at runtime, avoiding instantiations) if the output parameter is already
>> constructed.
>
> An output parameter is never constructed. This is important for
> exception safety.

Ok, then a non-const reference is an input-output parameter, I agree.
The issue is that we can't generate an optimal "func()" for :
A a;

a =...
a = func()

and

A a(func());

with the same "func()" definition. Inside func() we can't know if the
"output" value is going to be assigned to an already constructed object
or it will be used for copy-construction (with NRVO, in-place
construction). If it's going to be assigned, I want to reuse a's
resources as they are going to be discarded anyway. To get optimal code
I need to write two functions:

//function to construct from scratch using NRVO
A a(func_factory());

//function to modify A reusing its resources.
A a;
func_modify(a);

In C++03, func_modify() would be the choice of performance-conscious
programmers. In C++11, as we've told that "return by value is free" and
the syntax is more elegant, I'm afraid everyone will write
"func_factory". And func_factory() is less efficient when used in loops
and other situations where resource reusing is essential.

Regarding object construction order, NRVO makes some interesting things.
Say:

A func(A a3)
{
     a3.modify();
     return a3;
}

A a2 = func(A());

A() could be constructed in &a2 and a3 could be an alias for a2. The
return value could be already constructed before func() is called!

Let's think about a more "return like" syntax for multiple output
parameters:

//Declaration
A, B func(size_t num_elements);

//Definition
A a default(1, 2, 3), B b default(4,5) factory(size_t num_elements)
   //a & b are always constructed before function arguments
   //if not externally constructed (expression was in an assignment)
   //the default construction expression is used
{
    //a is a container, if a is already constructed, we don't
    //destroy elements
    a.resize(num_elements);
    for(size_t i = 0, max = a.size(); i != max; ++i){
       a[i] = ...;
    }

    //b is a string, if a is already constructed, reuse memory
    b = "abcdef";
    //implicit return of a & b
}

I don't see any problem with exception safety. If in runtime "factory()"
needs to construct a and b, the compiler can track it, just as I could
use placement new to construct them in my code inside an "if" condition.
So I could write:

A a;
a = ...
//b is copy constructed, a is assigned and resources where reused
[B b, a] = factory();

I agree this feature is very tricky, but I can't find any mechanism to
obtain optimal code with a single function. For single argument
functions you could provide two functions:

void reuse(A &a);

A factory()
{
   A a;
   reuse(a);
}

when the number of output parameters grow, then you need a lot of
overloads for each combination. Forgive me if this was too off-topic,
this is just an obsession I have with C++ output parameters!

Best,

Ion


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk