I have a very basic question: is it a good idea to return a std::vector<A> using std::move? For, example:
class A {};
std::vector<A> && func() {
std::vector<A> v;
/* fill v */
return std::move(v);
}
Should I return std::map, std::list.. etc... in this way?
You declare a function to return by r-value reference - this should almost never be done (if you return the local object by reference, you will end up with a dangling reference). Instead declare the function to return by value. This way the caller's value will be move constructed by the r-value returned by the function. The returned value will also bind to any reference.
Secondly, no, you should not return using an explicit std::move as this will prevent the compiler to use RVO. There's no need as the compiler will automatically convert any l-value reference returned to an r-value reference if possible.
std::vector<A> func() {
std::vector<A> v;
/* fill v */
return v; // 'v' is converted to r-value and return value is move constructed.
}
More info:
Using std::move() when returning a value from a function to avoid to copy
Is there any case where a return of a RValue Reference (&&) is useful?
No, it's not. This will in fact prevent copy elision in some cases. There is even a warning in some compilers about it, called -Wpessimizing-move.
In agreement with other answers, just return it by value, changing the return type to simply be std::vector<A>, and the compiler will take care of calling the move constructor when needed.
You could take a look at this post I just found, which seems to explain it in much detail (although I haven't read it through myself):
https://vmpstr.blogspot.hu/2015/12/redundant-stdmove.html
Both gcc and clang compiler with enabled optimization generate same binary code for both case when you return local variable and when you write std::move().
Just return a value.
But using && and noexcept specifier is useful if you create moving constructor and moving operator= for your custom class
Related
Is the following case of std::move superfluous?
std::string member;
obj(std::initializer_list<std::string> p_list)
: member {std::move(join(p_list))}
{}
This is the join function:
std::string join(string_initializer_list p_list) {
size_t size {};
for (auto const & s : p_list) {
size += s.size();
}
std::string output;
output.reserve(size);
for (auto const & s : p_list) {
output.append(s);
}
return output;
}
No, you don't need std::move. The function of std::move is to cast any value to an rvalue. Your function already returns an rvalue, thus the cast has no effect as far as binding the result to a reference is concerned (which is what you're after in order to initialize member from an rvalue).
In fact, using std::move actively inhibits copy elision, so it is a strict pessimization:
std::string s = join({}); // construct from prvalue, elidable,
// elision mandatory in C++17
std::string s = std::move(join({})); // temporary object must be constructed,
// s is initialized by moving from the
// temporary
In the first form, std::string s = join({});, copy elision means that the returned object of join is constructed directly in place of s (no temporary objects is constructed and copy or move is made), and moreover, the output variable in the function body is also elided and constructed directly in the return value, i.e. in s. With std::move, the first elision step is not available.
Given your join function is sane, and returns std::string, yes, the std::move would be superfluous; the return from join is an r-value already.
Beyond that, w/o std::move, copy elision means that it could construct the result in place without std::move, while using std::move could force it make a temporary string, invoke the move constructor to initialize member, then destroy the temporary; not a lot of work (a few pointer copies largely), but more than you need to do.
For clarity: any function that returns by value and hence returns an rvalue does not need std::move to be applied, and as others have already pointed out it is detrimental to performance optimisations.
e.g.
SomeClass fn()
{
...
}
// Move not needed, detrimental, as the function result is already an rvalue
SomeClass x = std::move(fn());
just do this as usual before c++11:
SomeClass x = fn();
Generally speaking use std::move(x) when x has a name. i.e. it is an identifier, it is not useful on temporaries except for special circumstances (in which you want to prevent copy elision, for example)
On a side note: Also don't try to use std::move to force the "strong exception gurantee" (for example when you want a struct wholly copied or left alone [i.e. consisent] in the face of potential exceptions.) as std::move can throw depending on the moved type and this type's exception policy can change under you. Instead use a wrapper function with a static assert combined with noexcept to enfore this at compile time. See Is there facility for a strong guaranteed exchange in C++
Often times I see transformer functions that will take a parameter by reference, and also return that same parameter as a function's return value.
For example:
std::string& Lowercase(std::string & str){
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return str;
}
I understand that this is done as a convenience, and I am under the impression that the compiler will optimize for cases when the return value is not actually used. However, I don't believe the compiler can optimize for newly created return values of non-basic types. For example:
std::tuple<int,std::string,float> function(int const& num, std::string const& str, float const& f){
return std::tuple<int,std::string,float>(num,str,f);
}
Constructors could do almost anything, and although the return type isn't used, it does not mean it would be safe to avoid creating the type. However, in this case, it would be advantageous to not create the type when the return value of the function isn't used.
Is there some kind of way to notify the compiler that if the return type is not being used, it's safe to avoid the creation of the type? This would be function specific, and a decision of the programmers; not something that the compiler could figure out on its own.
In the case of function and if the function is not inlined it might not optimize it since it has non trivial constructor. However, if the function is inlined it might optimize the unused return class if it's lifetime affects none of the arguments. Also since tuple is a standard type i believe most compiler will optimize that returned variable.
In general, there are two ways the compiler optimize your code:
(Named) Return value optimization (RVO/NRVO)
R-value reference
RVO
Take following code as example:
struct A {
int v;
};
A foo(int v) {
A a;
a.v = v;
return a;
}
void bar(A& a, int v) {
a.v = v;
}
A f;
f = foo(1);
A b;
bar(b, 1);
In function foo, the variable a is constructed, modify its member v, and returns. In an human-optimized version bar, a is passed in, modified, and gives to caller.
Obviously, f and b are the same.
And if you know more about C++, you will know in returning from foo, result a is copied to outer f, and the dtor of a is called.
The way to make optimized foo into bar is called RVO, it omits the copy of internal a to outer f. Modification directly goes to variable of caller.
Please beware, there are cases RVO won't apply: copy ctor has side effect, multiple returns, etc.
Here is a detailed explaination:
MSDN
CppWiki
RValue
Another way to optimize return value is to use rvalue ctor introduced in C++ 11. Generally speaking, it's like calling std::swap(vector_lhs, vector_rhs) to swap the internal data pointer to avoid deep copy.
Here is a very good article about optimization:
http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/
Last but not least
In Going Native 2013, Andrei Alexandrescu gave a talk about how to write quick C++ code. And pass by reference is faster than rvalue. (Also RVO has some limitations) So if you do care about performance, please use pass by reference.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++11 rvalues and move semantics confusion
What I think is correct is
std::string GetLine()
{
std::string str;
std::getline(std::cin, str);
return std::move(str);
}
But at this link http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html
( check the header part Returning an explicit rvalue-reference from a function)
which is #1 google search hit for move semantics shows a similar function signature as
int&& GetInt()
{
int x = 0;
// code here
return std::move(x);
}
From what I read at other places && means rvalue reference so in this case its returning a reference to an object that doesn't exist.
So which is it?
(Yes I know moving an int has no real benifit but the question is whether to use the return type of std::string or std::string&& in the first function. And if that is how it should be done for all types.)
You are absolutely correct that the int&& GetInt() example is wrong, and is returning a reference to an object that is destroyed. However, unless I missed it, the link you posted does not actually show any code returning a reference to a local variable. Instead I see a reference to a global variable being returned, which is okay.
Here is how you use move semantics when returning:
std::string func()
{
std::string rv;
/* ... */
return rv;
}
You generally should not use std::move() when returning an object. The reason for this is that moving is already implicitly allowed anytime RVO could occur, and using std::move() will suppress RVO. So using std::move() will never be better and will often be worse than just returning normally.
Again, using std::move() can be worse than simply naming the variable to be returned because it suppresses the return value optimization. The return value optimization allows for an object to be returned to the caller without needing to copy that object
in a return statement in a function with a class return type, when
the expression is the name of a non-volatile automatic object (other
than a function or catch-clause parameter) with the same
cv-unqualified type as the function return type, the copy/move
operation can be omitted by constructing the automatic object directly
into the function’s return value
— [class.copy] 12.8/31
But using std::move() prevents the return expression from being the name of the object you're returning. Instead the expression is more complicated and the language is no longer allowed to give it special handling.
The reason just naming the object is not worse than using std::move() is because there's another rule that says an expression can already be treated as an rvalue without needing std::move().
When the criteria for elision of a copy operation are met or would be
met save for the fact that the source object is a function parameter,
and the object to be copied is designated by an lvalue, overload
resolution to select the constructor for the copy is first performed
as if the object were designated by an rvalue.
Answering the question, sort of: return a string. Don't move anything, but rather use (rely on) RVO:
std::string func()
{
std::string rv;
/* ... */
return rv;
}
This is how it generally should be done. You can't return an (r-value or not) reference to a temporary.
No need to say return std::move(str); if str is a local variable: If the variable satisfies the criteria for return-value optimisation, then in a return statement the variable will bind to an rvalue reference.
Also, beware that you should probably not return a reference to a local variable, neither lvalue nor rvalue reference.
All told, you should have:
int foo() { int x; /*...*/ return x; }
std::string bar() { std::string str; /*...*/ return str; }
I've lost one hour to find this problem in my code:
vector<string> & input_variables = parse_xml(xml_path)["variables"];
where parse_xml is a function returning a std::map<std::string, std::vector<std::string> >. Why gcc is not warning me (with -Wall)? Am I missing some flags?
You have taken a reference to an object which is destroyed. In C++11 new language features are written in making this code illegal. You must make a copy or swap the data into a local variable if you wish to use it. GCC is not warning you because C++03 does not provide the necessary features to prevent such.
Technically, the return value of operator[] is an lvalue. Unfortunately, it is about to be destroyed by it's owner, the std::map.
GCC doesn't warn you because technically there's nothing to warn about.
parse_xml() returns a std::map by value, which is a temporary. Calling operator[] returns a reference. The compiler cannot know locally that this reference is actually part of the std::map temporary. For all the compiler knows, operator[] could be returning a reference to a global or something.
A member variable of a temporary is considered a temporary, which is linked to the lifetime of the outer temporary. But the return value of a function (like operator[]) is not so linked.
The reason why it doesn't warn you is because you are getting an invalid operation through a sequence of valid steps:
struct X
{
int c;
int & operator [] (int) { return c; } /* this is perfectly OK */
};
X f()
{
return X(); /* this is perfectly OK */
}
int main()
{
int &x = f()[1]; /* can apply [] on temporary, therefore OK */
}
You can prevent this from occurring by explicitly marking the result of f() as const.
I would like to implement a function that fills up a vector and then returns an rvalue reference. I tired something like:
std::vector<int> &&fill_list() {
std::vector<int> res;
... do something to fill res ...
return res;
}
int main(int argc, char **argv) {
std::vector<int> myvec = fill_list();
return 0;
}
but that doesn't work, I get the following error:
error: invalid initialization of reference of type 'std::vector<int>&&' from expression of type 'std::vector<int>'
So, all in all, how is the right way of doing it? I don't think I get rvalue references just yet.
You seem to be confused as to what an rvalue reference is and how it relates to move semantics.
First thing's first: && does not mean move. It is nothing more than a special reference type. It is still a reference. It is not a value; it is not a moved value; it is a reference to a value. Which means it has all of the limitations of a reference type. Notably, it must refer to a value that still exists. So returning a dangling r-value reference is no better than returning a dangling l-value reference.
"Moving" is the process of having one object claim ownership of the contents of another object. R-value references facilitate move semantics, but simply having a && does not mean anything has moved. Movement only happens when a move constructor (or move assignment operator) is called; unless one of those two things is called, no movement has occurred.
If you wish to move the contents of a std::vector out of your function to the user, you simply do this:
std::vector<int> fill_list() {
std::vector<int> res;
... do something to fill res ...
return res;
}
Given this usage of fill_list():
std::vector<int> myvec = fill_list();
One of two things will happen. Either the return will be elided, which means that no copying or moving happens. res is constructed directly into myvec. Or res will be moved into the return value, which will then perform move-initialization of myvec. So again, no copying.
If you had this:
std::vector<int> myvec;
myvec = fill_list();
Then again, it would be moved into. No copying.
C++11 knows when it's safe to implicitly move things. Returning a value by value rather than by reference or something is always a safe time to move. Therefore, it will move.
The return statement is an error because you atempt to bind an rvalue reference (the return type) to an lvalue (the vector res). An rvalue reference can only be bound to an rvalue.
Also, as others already mentioned, returning a local variable when the return type is a reference type is dangerous, because the local object will be destroyed after the return statement, then you get a reference that refers to an invalid object.
If you want to avoid the copy construction during the return statement, just using a non-reference type might already works due to a feature called copy elision. the vector res in your fill_list function may be directly constructed into the vector myvec in your main function, so no copy or move construction is invoked at all. But this feature is allowed by Standard not required, some copy construction is not omitted in some compiler.
For a discussion of rvalue references you can read what Bjarne Stroustrup, the author of C++, has to say about them here:
http://www2.research.att.com/~bs/C++0xFAQ.html#rval
Addressing your specific example, the short answer is that due to the Named Return Value Optimization - which is a de facto standard C++ compiler feature even pre-C++11 - if you simply return-by-value the compiler will tie up res and myvec efficiently like you want:
std::vector<int> fill_list() {
std::vector<int> res;
... do something to fill res ...
cout << &res << endl; // PRINT POINTER
return res;
}
int main(int argc, char **argv) {
std::vector<int> myvec = fill_list();
cout << &myvec << endl; // PRINT POINTER
return 0;
}
The two "PRINT POINTER" lines will print the same pointer in both cases.
The vector myvec and the vector res in the above will be the same vector with the same storage. No copy constructor or move constructor will be called. In a sense res and myvec will be two aliases of the same object.
This is even better than using a move constructor. myvec is constructed and "filled up" in-place.
The compiler achieves this by compiling the function in an "inplace" mode overlaying an immediate stack position in the callers stack frame with the callees local result variable, and simply leaving it there after the callee returns.
In this circumstance we say that the constructor has been elided. For more information see here:
http://en.wikipedia.org/wiki/Return_value_optimization
In the event that you were assigning the result of fill_list in a non-constructor context, than as a return-by-value results in an xvalue (short for "expiring" value, a type of rvalue), the move assignment operator of the target variable would be given preference if it is available.
If you just remove the && from your function it should work, but it will not be a reference. fill_list() will create a vector and return it. During the return a new vector will be created. The first vector that was created inside fill_list() will be copied to the new vector and then will be destroyed. This is the copy constructor's work.