Prev: Can there be parallel initialization of global variables in C++0x?
Next: Can const& functors be passed to functions efficiently (i.e. inlined, etc)?
From: DeMarcus on 27 May 2010 17:06 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 28 May 2010 02:11 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 28 May 2010 05:07 > 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 29 May 2010 08:38
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! ] |