From: DeMarcus on
Hi,

Let's say I have this function.

std::vector<std::string> fnc()
{
std::vector<std::string> vec;

while( youDontWantToWaitThisLong() )
{
vec.push_back( getSomeData() );
}

return vec;
}

As I understand, the use of rvalue references and the movement of data
will take effect when I do one single change to the above function:

return std::move( vec );

And moreover, as I understand, this will also compile even though the
return value is of a type that has not implemented the move constructor
MyClass( MyClass&& );

Therefore, it would be natural to just put std::move everywhere a
function returns by value (and the data needs no copy).

Now, am I guaranteed that std::move will be as efficient as RVO when the
returned type has implemented the move constructor?

What are the guidelines using std::move? Shall I start put it everywhere
I return by value?


Thanks,
Daniel


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

From: Paul Bibbings on
DeMarcus <use_my_alias_here(a)hotmail.com> writes:

> Hi,
>
> Let's say I have this function.
>
> std::vector<std::string> fnc()
> {
> std::vector<std::string> vec;
>
> while( youDontWantToWaitThisLong() )
> {
> vec.push_back( getSomeData() );
> }
>
> return vec;
> }
>
> As I understand, the use of rvalue references and the movement of data
> will take effect when I do one single change to the above function:
>
> return std::move( vec );
>
> And moreover, as I understand, this will also compile even though the
> return value is of a type that has not implemented the move constructor
> MyClass( MyClass&& );
>
> Therefore, it would be natural to just put std::move everywhere a
> function returns by value (and the data needs no copy).
>
> Now, am I guaranteed that std::move will be as efficient as RVO when the
> returned type has implemented the move constructor?
>
> What are the guidelines using std::move? Shall I start put it everywhere
> I return by value?

As I understand it I believe that you will not be doing yourself any
favours here and may actually be introducing *extra* copying for the
case where the return type has not implemented the move constructor.

Take the following as an example:

10:19:35 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPPM $cat move_everywhere.cpp
// file: move_everywhere.cpp

#include <iostream>
#include <string>
#include <utility>

class MyClass {
std::string s_;
public:
MyClass(std::string s)
: s_(s)
{ std::cout << "ctor\n"; }
MyClass(const MyClass& mc)
: s_(mc.s_)
{ std::cout << "copy\n"; }
MyClass(MyClass&& mc)
: s_(std::move(mc.s_))
{ std::cout << "move\n"; }
};

MyClass func()
{
MyClass tmp("Hello");

return tmp;
}

int main()
{
func();
}

10:19:47 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPPM $i686-pc-cygwin-g++-4.5.0 -O3
-std=c++0x -o move_everywhere move_everywhere.cpp

10:19:59 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPPM $./move_everywhere
ctor

Then, taking the following in stages (accumulatively, using the same
build options to g++):

1. change func to use std::move (note: MyClass has a move constructor):

MyClass func()
{
MyClass tmp("Hello");

return std::move(tmp);
}

10:23:17 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPPM $./move_everywhere
ctor
move

Here, std::move will add an efficiency since MyClass has a move
constructor which, in turn, invokes the move constructor on
std::string. However...

2. remove the move constructor from MyClass:

10:26:30 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPPM $./move_everywhere
ctor
copy

and you have an extra copy over the orignal version of func (without
std::move). This, remember, is with the same optimisation (and, hence,
with the same opportunities for RVO).

3. Change func to return by rvalue-reference:

MyClass&& func()
{
MyClass tmp("Hello");

return std::move(tmp);
}

10:29:30 Paul Bibbings(a)JIJOU
/cygdrive/d/CPPProjects/CLCPPM $./move_everywhere
ctor

and you have the maximum optimisation again, even though we have not put
back the move constructor. Put the move constructor back in and we are
`cooking on gas' (as we say where I come from :).

So, it seems to me that there is some sense in which doing what you
propose actually interferes with RVO (perhaps) or, at least, introduces
extra copying when used in relation to return by value; and I think I
would have expected that too.

In short, I believe (only) that use of std::move in a return statement
is a form that you would use in relation to a return by rvalue-reference
only in this instance.

In any case, it does not seem that a `blanket' use of std::move is wise
at all and that, like everything else, its use should always be
considered judiciously in relation to the merits of the case.

Regards

Paul Bibbings

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

From: Ahmed Charles on
> As I understand, the use of rvalue references and the movement of data
> will take effect when I do one single change to the above function:
>
> return std::move( vec );

Rvalue references will take place without the addition of std::move,
because the value vec can be treated like an rvalue when determining
which constructor overload to call and will consider move
constructors. n3092 6.6.3/2 [ Note: A copy or move operation
associated with a return statement may be elided or considered as an
rvalue for the purpose of overload resolution in selecting a
constructor (12.8). -end note ]

So, you don't need std::move at all for return values.


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

From: Andy Venikov on
DeMarcus wrote:
> Hi,
>
> Let's say I have this function.
>
> std::vector<std::string> fnc()
> {
> std::vector<std::string> vec;
>
> while( youDontWantToWaitThisLong() )
> {
> vec.push_back( getSomeData() );
> }
>
> return vec;
> }
>
<snip>

Any non-reference lvalue in the return statement of a function that
returns a non-reference becomes an rvalue.

Sorry, I don't have a reference to the standard clause. But it makes
sense, since after you type "return vec" no one is able to access your
"vec", and it's safe to assume that for all intents and purposes it's an
rvalue. (See http://www.drdobbs.com/184403855, where Andrei says pretty
much the same thing about return statements).

So, move isn't necessary here.


Also refer to this thread, where recently I had a very similar question:

http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/a700e0c69c8b5346/b9cb6683f4c188ad



> Thanks,
> Daniel
>
>

Andy.

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