Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   C++11 rvalue reference question (http://www.velocityreviews.com/forums/t806597-c-11-rvalue-reference-question.html)

Andrew Tomazos 12-05-2011 05:38 AM

C++11 rvalue reference question
 
class O {...};
class I {...};
class E {...};

Suppose we have some function f that takes an instance of class I as
input and produces an instance of class O as output (throwing an
instance of class E on an error):

O f(const I& i)
{
O result;
... // mutate result based on i
if (...)
throw E(...);

return result;
}

I i = ...;
O o = f(i);

In C++03 many times it was recommend to write such a function as
follows:

void f(O& out, const I& i)
{
.... // mutate result based on i
if (,,,)
throw E(...);
}

I i = ...;
O o;
f(o,i);

I suspect this is to avoid the (potentially expensive) copy
construction as the temporary O instance is copied from f's stack
frame to the callers.

The downside is that you then can't do things like:

f(i).callSomeOFunction()

or

someFunctionTakingAnO(f(i))

My question is with the advent of move constructors, xvalues and
rvalue references in C++11, is there anyway to address this issue?

What would this mean/do:

O&& f(const I& i)
{
O result;
... // mutate result based on i
if (...)
throw E(...);

return result; // or std::forward(result) ?
}

or is it broken?

Thanks,
Andrew.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Daniel Krügler 12-05-2011 11:44 PM

Re: C++11 rvalue reference question
 
On 2011-12-05 06:38, Andrew Tomazos wrote:
> class O {...};
> class I {...};
> class E {...};
>
> Suppose we have some function f that takes an instance of class I as
> input and produces an instance of class O as output (throwing an
> instance of class E on an error):
>
> O f(const I& i)
> {
> O result;
> ... // mutate result based on i
> if (...)
> throw E(...);
>
> return result;
> }


OK, so far.

> I i = ...;
> O o = f(i);
>
> In C++03 many times it was recommend to write such a function as
> follows:
>
> void f(O& out, const I& i)
> {
> .... // mutate result based on i
> if (,,,)
> throw E(...);
> }
>
> I i = ...;
> O o;
> f(o,i);
>
> I suspect this is to avoid the (potentially expensive) copy
> construction as the temporary O instance is copied from f's stack
> frame to the callers.
> The downside is that you then can't do things like:
>
> f(i).callSomeOFunction()
>
> or
>
> someFunctionTakingAnO(f(i))


Yes.

> My question is with the advent of move constructors, xvalues and
> rvalue references in C++11, is there anyway to address this issue?
>
> What would this mean/do:
>
> O&& f(const I& i)
> {
> O result;
> ... // mutate result based on i
> if (...)
> throw E(...);
>
> return result; // or std::forward(result) ?
> }
>
> or is it broken?


This *is* broken, for the simple reason that this will produce a
"dangling" reference to an automatic object that has been locally
created in the function and that has been destroyed before the function
call ends. Don't do that!

Make it simple, just use return type O (without cv-qualifiers). The
language has intentionally been adapted to enforce the compiler to first
check whether the local object "result" can be be provided as an rvalue
to the return statement to enable move semantics if the type provides some.

HTH & Greetings from Bremen,

Daniel Krügler


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Arne L 12-05-2011 11:51 PM

Re: C++11 rvalue reference question
 
On Dec 5, 6:38 am, Andrew Tomazos <and...@tomazos.com> wrote:
> ...
> My question is with the advent of move constructors, xvalues and
> rvalue references in C++11, is there anyway to address this issue?
>
> What would this mean/do:
>
> O&& f(const I& i)
> {
> O result;
> ... // mutate result based on i
> if (...)
> throw E(...);
>
> return result; // or std::forward(result) ?
>
> }
>
> or is it broken?


That is broken. Never return rvalue references from functions.
Return by value instead. Even in C++98, there will be no
temporary in almost all cases. Search for "return value
optimization" and "named return value optimization".

rvalue references are primarily useful in the "perfect
forwarding" scenario, as well as during construction/
assignment of objects from function return values.

I i; // default constructor need be defined
O o = f(i);

In the second line, if RVO and NRVO fail, C++98
will call the copy constructor, meaning copying
of a temporary. In C++11, the move constructor
will be invoked (if it is defined), meaning NO
temporary will be copied. Note that RVO and
NRVO are frequently applicable (and you need
to do nothing to profit from it), so move
assignment may be more commonly profitable:

I i;
O o;
o = f(i);

In C++98, this will create a temporary in line 3,
neccessitating copying. In C++11, the move
assignment operator will be called (if it is defined),
meaning no copying will be performed.

In short: use return by value generously. Classes
from the standard library implement move semantics,
so don't be afraid to return them by value;

If you are writing your own classed (which own
resources), consider giving them move construction
and move assignment operator functions (as described
elsewhere).

Note that, generally, if you define one of the "big 5"
(destructor, copy ctor, assignment operator, move
ctor, move assignment operator), you will need to
define all 5. (Previously called the Rule Of The Big Three).

Greetings
Arne Luenser


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Dave Abrahams 12-06-2011 07:59 PM

Re: C++11 rvalue reference question
 
on Mon Dec 05 2011, Andrew Tomazos <andrew-AT-tomazos.com> wrote:

> In C++03 many times it was recommend to write such a function as
> follows:
>
> void f(O& out, const I& i)
> {
> .... // mutate result based on i
> if (,,,)
> throw E(...);
> }
>
> I i = ...;
> O o;
> f(o,i);
>
> I suspect this is to avoid the (potentially expensive) copy
> construction as the temporary O instance is copied from f's stack
> frame to the callers.


Probably, but the code above has always been a bad idea even in C++03.
Every compiler implements copy elision, so

O o = f(i);

is bound to be just as efficient, if not more so.

http://cpp-next.com/archive/2009/08/...pass-by-value/

Cheers,

--
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! ]

SG 12-06-2011 08:00 PM

Re: C++11 rvalue reference question
 
On 6 Dez., 00:51, Arne L wrote:
> On Dec 5, 6:38 am, Andrew Tomazos wrote:
> > ...
> > My question is with the advent of move constructors, xvalues and
> > rvalue references in C++11, is there anyway to address this issue?


Yes. Make your type movable without using any && outside of move ctors
and move assignment operators. && is NOT some kind of compiler magic
that makes anything movable. It's there to ALLOW you to write MOVABLE
types.

> [...]
> Note that, generally, if you define one of the "big 5"
> (destructor, copy ctor, assignment operator, move
> ctor, move assignment operator), you will need to
> define all 5. (Previously called the Rule Of The Big Three).


No, it's not *that* bad. The rule of three still remains the rule of
three, basically. And if it weren't for a little exception (C++03
compatibility) to a really simple new rule (about compiler-generated
copy/move operations), we wouldn't even need the rule of three
anymore. Luckily, this exception is deprecated which is why we now can
expect compilers to warn about rule-of-three violations. The simple
rule I was referring to earlier is:

- If you define any of the 5, the compiler won't generate any
other copy/move operations.

Obviously this is not compatible with existing C++03 code. So, unless
you declare a custom move operation (ctor or assignment or both) we're
back to C++03 rules w.r.t. compiler-generated operations.

So, if we put this together we'll get:

- user-declared move operations inhibit the generation of
all other copy/move operations.

- user-declared dtor or copy operations inhibit the
generation of all other move operations
(but not yet the remaining copy operations due to
C++03 compatibility)

I think it's safe to say that the situation actually improved.

Cheers!
SG


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Ebenezer 12-11-2011 08:52 AM

Re: C++11 rvalue reference question
 
On Dec 6, 1:59 pm, Dave Abrahams <d...@boostpro.com> wrote:
> on Mon Dec 05 2011, Andrew Tomazos <andrew-AT-tomazos.com> wrote:
> > In C++03 many times it was recommend to write such a function as
> > follows:

>
> > void f(O& out, const I& i)
> > {
> > .... // mutate result based on i
> > if (,,,)
> > throw E(...);
> > }

>
> > I i = ...;
> > O o;
> > f(o,i);

>
> > I suspect this is to avoid the (potentially expensive) copy
> > construction as the temporary O instance is copied from f's stack
> > frame to the callers.

>
> Probably, but the code above has always been a bad idea even in C++03.
> Every compiler implements copy elision, so
>
> O o = f(i);
>
> is bound to be just as efficient, if not more so.
>


I agree that's nice, but in a marshalling context, the other
form is able to handle multiple outputs better

O1 o1;
O2 o2;
Msgs.Receive(buf, o1, o2);


Brian Wood
Ebenezer Enterprises
http://webEbenezer.net


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


All times are GMT. The time now is 08:44 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.