Is it legal to have a rvalue refrence of a lvalue reference ?
Considering the following example, is there a difference between the two cases in the final rvalueRef in term of what it refer to or type (or others things)?
Type& ref = GetReference()
Type&& rvalueRef = std::move(ref)
vs
Type value = GetValue()
Type&& rvalueRef = std::move(value)
Both code is correct and 100% legal in C++. There is a difference only in the sense that in the first case a reference is moved (or better say, capable of being moved if appropriate destination is used) and in second case, it is the copy (see the example below for clarification on this).
Note that std::move does NOT actually move the object. It only casts the object into a rvalue reference type. That is all.
Also note that in both cases, rvalueRef is still an lvalue — an object which has a name (i.e an identifier to refer to) is never an rvalue. So if you don't actually move it using std::move (or using explicit cast) again, then there is no difference at all.
Here is a concrete example:
//given function
std::string& GetReference();
std::string GetValue();
//target function
void f(std::string param);
And your code follows:
std::string& ref = GetReference();
std::string&& rvalueRef = std::move(ref);
std::string value = GetValue()
std::string&& rvalueCopy = std::move(value); //named changed
till now NO DIFFERENCE at all.
But if you do this:
f(std::move(rvalueRef)); //actual object returned from GetReference is moved!
f(std::move(rvalueCopy)); //only a copy is moved.
The actual object is moved in the first case, and in the second case, the copy is moved. It doesn't make any difference at all if you do this:
f(std::move(GetReference())); //actual object returned from GetReference is moved!
f(std::move(GetValue())); //only a copy is moved.
So you see, in your code, there is no difference because there is NO ACTUAL MOVE at all. Only cast is there. To have an actual move, there should be an appropriate target type which could invoke move-constructor or move-assignment! In your case, there is NO invocation of either.
Q. Is it legal to have a rvalue refrence of a lvalue reference?
That's not really the question you are asking. The question you are really asking is this:
Q. Is it legal to cast an lvalue reference to an rvalue reference?
The answer is yes. std::move just casts its argument to an rvalue reference, which is always legal. The overall correctness of what you are doing depends on what you then do with the result of std::move. There is nothing wrong with your example code.
Q. Is there a difference between these two cases?
// case 1 // case 2
Type& ref = GetReference(); Type value = GetValue();
f(std::move(ref)); f(std::move(value));
The only difference is that in case 1, ref is a reference to the object returned by GetReference(), but in case 2, value is a copy of the object returned by GetValue().
Related
If I keep a constant reference to a non-reference returned value of a function in C++11, where does the reference point in the stack? And is it safe to do so?
string foo() {
std::string foo_ret = "foo string";
return foo_ret;
}
int main() {
const std::string& a = foo();
}
Your code is illegal; non-const lvalue references may not bind to rvalues. There's not really a good reason behind this, it's just a language rule that was introduced very early on in C++'s history.
MSVC used to (maybe still does) allow this binding, I can't comment on how MSVC implements it.
You can bind to other reference types though:
std::string const &a = foo(); // (1)
std::string&& b = foo(); // (2)
In case (2), b binds directly to the return value object, which has its lifetime extended to match b's lifetime. Note: no "move" operation occurs here, it is just binding a reference.
In case (1), conceptually, a temporary of type const std::string is initialized from the return value, and that temporary has its lifetime extended to match a's lifetime. In practice this copy will be elided. your code will behave as if the reference bound directly to the return value.
Generally speaking, you should use value semantics. std::string c = foo(); is the safest option. Because of copy elision, it is not any less efficient than the reference options.
The main danger with the reference option is that if the function were changed to return a reference, then a or b may become a dangling reference.
No it is not safe to do so, and it is an error and will not compile.
You might be looking for R Value references: http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html
In my opinion, it is legal to to do.
When you return a string from the function, it returns a Rvalue or temporary object. You can not use normal Lvalue reference to fetch the Rvalue but you can use const Lvalue reference to fetch. When you use const Lvalue reference, the life time of the temporary object is extended to be the same as the reference does.
As for where the reference point to in the memory, I guess it may vary by implementation. But what matters here is that the temporary object is no longer 'temporary', although you can not change it.
//old school '98 c++, no C++0x stuff
std::string getPath();
void doSomething()
{
const std::string &path = getPath(); //const reference to an rvalue
... // doSomething with path
}
void doSomething2()
{
const std::string path = getPath(); //regular variable
... // doSomething with path
}
what are the differences between doSomething and doSomething2 and which one is prefferable?
Is it safe to use const reference to returned rvalue in doSomething?
Does doSomething2 create a copy of returned rvalue, is compiler allowed to do rvalue optimization here?
Is it safe to use const reference to returned rvalue in doSomething?
Yes, this is perfectly fine. The language has an specific clause that guarantees that if you bind a reference to an rvalue a temporary is created and the lifetime is extended until the end of the scope where the reference is created.
Does doSomething2 create a copy of returned rvalue, is compiler allowed to do rvalue optimization here?
In both cases the cost is the same, as the compiler will do RVO (return value optimization)
what are the differences between doSomething and doSomething2 and which one is prefferable?
The main difference is that in one case you are giving a name to the real object and in the other case the name is given to a reference. The compiler should generate exactly the same code in both versions.
That being said, I find the use of the const& to be misleading. It gives the impression that the local function has a reference to some object somewhere, but it really has a copy (with no name). To realize that this is a copy the maintainer will have to look and verify the signature of the function that is being called. In the case of the value the behavior is more obvious: the function maintains a copy of whatever is returned by the function (which might be a value or reference).
The second difference is that you are only legally allowed to bind a const reference, which means that the function cannot modify the object. In the case of storing a value, the type can be non-const and the function could modify that object, so the approach is more flexible.
In C++03 the only reason to use the const& trick is in the case where you know that the function returns a value, you know that the type derives from a well known base, and you don't want to name the type [Take a look at ScopeGuard]. In C++11 that use is no longer important, as you can just use auto to let the compiler figure out the type automatically.
(from other comments it seems this might be C++ standards version dependant as to guarentees when you bind a reference to an rvalue about its lifespan - this answer reflects C++ classic)
doSomething has a reference to what?
doSomething2 has a copy of something that may not exists anymore which is fine
lets look at getPath():
in general it will take the return value, copy it to the stack and then copy that to the lhs
it can just assign directly to the lhs
it can return "hello" which will create a string on the stack - this cannot be referenced because it is temporary (the problem with doSomething)
it can return a static const string - in which case it can be completely inlined and assigned to the lhs
The reference version could have a dangling reference if the std::string was allocated inside the function getPath() and destroyed when returning from that function.
Then, it's dangerous usage.
If you had a class holding that string and the class outlives the scope of that const std::string & reference, something as MyClass::getPath(), then, in that case, the reference wouldn't be dangling.
The second version will always work.
I am trying to understand rvalue reference and move semantics. In following code, when I pass 10 to Print function it calls rvalue reference overload, which is expected. But what exactly happens, where will that 10 get copied (or from where it referred). Secondly what does std::move actually do? Does it extract value 10 from i and then pass it? Or it is instruction to compiler to use rvalue reference?
void Print(int& i)
{
cout<<"L Value reference "<<endl;
}
void Print(int&& i)
{
cout<<"R Value reference "<< endl;
}
int main()
{
int i = 10;
Print(i); //OK, understandable
Print(10); //will 10 is not getting copied? So where it will stored
Print(std::move(i)); //what does move exactly do
return 0;
}
Thanks.
In the case of a 10, there will probably be optimisations involved which will change the actual implementation, but conceptually, the following happens:
A temporary int is created and initialised with the value 10.
That temporary int is bound to the r-value reference function parameter.
So conceptually, there's no copying - the reference will refer to the temporary.
As for std::move(): there may be some tricky bits related to references etc., but principally, it's just a cast to r-value reference. std::move() does not actually move anything. It just turns its argument into an r-value, so that it can be moved from.
"Moving" is not really a defined operation, anyway. While it's convenient to think about moving, the important thing is l-value vs. r-value distinction.
"Moving" is normally implemented by move constructors, move assignment operators and functions taking r-value references (such as push_back()). It is their implementation that makes the move an actual move - that is, they are implemented so that they can "steal" the r-value's resources instead of copying them. That's because, being an r-value, it will no longer be accessible (or so you promise the compiler).
That's why std::move() enables "moving" - it turns its argument into an r-value, signalling, "hey, compiler, I will not be using this l-value any more, you can let functions (such as move ctors) treat it as an r-value and steal from it."
But what exactly happens, where that 10 will get copied (or from where it referred)
A temporary value is created, and a reference passed to the function. Temporaries are rvalues, so can be bound to rvalue references; so the second overload is chosen.
Secondly what std::move actually do?
It gives you an rvalue reference to its argument. It's equivalent (by definition) to static_cast<T&&>.
Despite the name, it doesn't do any movement itself; it just gives you a reference that can be used to move the value.
std::move cast int in int&& via static_cast<int&&>.
Eventually if the type is a class or a struct, the move constructor if it is defined (implicitly or explicitly) will be invoked instead of the copy constructor/classical constructor.
I have been coding in C++ for past few years. But there is one question that I have not been able to figure out. I want to ask, are all temporaries in C++, rvalues?
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
No.
The C++ language specification never makes such a straightforward assertion as the one you are asking about. It doesn't say anywhere in the language standard that "all temporary objects are rvalues". Moreover, the question itself is a bit of misnomer, since the property of being an rvalue in the C++ language is not a property of an object, but rather a property of an expression (i.e. a property of its result). This is actually how it is defined in the language specification: for different kinds of expressions it says when the result is an lvalue and when it is an rvalue. Among other things, this actually means that a temporary object can be accessed as an rvalue as well as an lvalue, depending on the specific form of expression that is used to perform the access.
For example, the result of literal 2 + 3 expression is obviously an rvalue, a temporary of type int. We cannot apply the unary & to it since unary & requires an lvalue as its operand
&(2 + 3); // ERROR, lvalue required
However, as we all know, a constant reference can be attached to a temporary object, as in
const int &ri = 2 + 3;
In this case the reference is attached to the temporary, extending the lifetime of the latter. Obviously, once it is done, we have access to that very same temporary as an lvalue ri, since references are always lvalues. For example, we can easily and legally apply the unary & to the reference and obtain a pointer to the temporary
const int *pi = &ri;
with that pointer remaining perfectly valid as long as the temporary persists.
Another obvious example of lvalue access to a temporary object is when we access a temporary object of class type through its this pointer. The result of *this is an lvalue (as is always the case with the result of unary * applied to a data pointer), yet it doesn't change the fact that the actual object might easily be a temporary. For a given class type T, expression T() is an rvalue, as explicitly stated in the language standard, yet the temporary object accessed through *T().get_this() expression (with the obvious implementation of T::get_this()) is an lvalue. Unlike the previous example, this method allows you to immediately obtain a non-const-qualified lvalue, which refers to a temporary object.
So, once again, the very same temporary object might easily be "seen" as an rvalue or as an lvalue depending on what kind of expression (what kind of access path) you use to "look" at that object.
Prasoon Saurav already linked a very good clc++ thread. In there, James Kanze explains why the question doesn't really make sense. It boils down to:
rvalue-ness is a (boolean) property of expressions - each expression is either an lvalue or an rvalue
temporaries are not expressions
For that reason, the question doesn't make sense.
A good example is the following code:
int main() {
const int& ri = 4;
std::cout << ri << std::endl;
}
The temporary int with value 4 is not an expression. The expression ri that's printed is not a temporary. It's an lvalue, and refers to a temporary.
well, that array operator returns a reference, any function that returns a reference could be considered to do the same thing? all references are const, while they can be lvalues, they modify what they reference, not the reference itself. same is true for the *operator,
*(a temp pointer) = val;
I swear I used to use some compiler that would pass temp values to any function that took a reference,
so you could go:
int Afunc()
{
return 5;
}
int anotherFunc(int & b)
{
b = 34;
}
anotherFunc(Afunc());
can't find one that lets you do that now though, the reference has to be const in order to allow passing of temp values.
int anotherFunc(const int & b);
anyway, references can be lvalues and temporary, the trick being the reference it's self is not modified, only what it references.
if you count the-> operator as an operator, then temporary pointers can be lvalues, but the same condition applies, its not the temp pointer that would be changed, but the thing that it points to.
An array indexing operation is both a temporary and an lvalue, something like a[10] = 1 is an example of what you're looking for; the lvalue is a temporary, calculated pointer.
Short answer: yes, but I'm not going to quote the standard, because proving the point would require addressing every kind of temporary there is. By definition a temporary has a lifetime of one statement, so assigning things to one would be poor style at best.
Interesting answer: Copy elision can make (often makes) a temporary object identical with an lvalue object. For example,
MyClass blah = MyClass( 3 ); // temporary likely to be optimized out
or
return MyClass( 3 ); // likely to directly initialize object in caller's frame
Edit: as for the question of whether there is any temporary object in those cases, §12.8/15 mentions
the copy operation can be omitted by constructing the temporary object directly into the target of the omitted copy
which would indicate that there is a temporary object which may be identical with an lvalue.
It depends on what you consider a temporary variable is. You can write something like
#include <stdio.h>
int main()
{
char carray[10];
char *c=carray+1;
*(c+2+4) = 9;
printf("%d\n",carray[7]);
return 0;
}
This runs in VisualStudios and GCC. You can run the code in codepad
I consider (c+2+4) a rvalue although i want to assign to it. When i dereference it, it would become an lvalue. So yes all temporaries are rvalues. But you can make rvalues (thus a temporary) into an lvalue by dereferencing it
If no, can anyone provide me an example where temporary produced in the code is an lvalue?
The following code binds a constant reference to a temporary object of type const float created by the compiler:
int i;
const float &cfr = i;
The behaviour is "as if":
int i;
const float __tmp_cfr = i; // introduced by the compiler
const float &cfr = __tmp_cfr;
One of the cool new features of the upcoming C++ standard, C++0x, are "rvalue references." An rvalue reference is similar to an lvalue (normal) reference, except that it can be bound to a temporary value (normally, a temporary can only be bound to a const reference):
void FunctionWithLValueRef(int& a) {…}
void FunctionWithRValueRef(int&& a) {…}
int main() {
FunctionWithLValueRef(5); // error, 5 is a temporary
FunctionWithRValueRef(5); // okay
}
So, why did they invent a whole new type, instead of just removing the restrictions on normal references to allow them to be bound to temporaries?
It would be pointless. You would change the thing in the function, and the change would be lost immediately because the thing was actually a temporary.
The reason for the new type stems from the need to be able to decide what actually is an rvalue and what not. Only then you can actually use them for the cool things they are used.
string toupper(string && s) { // for nonconst rvalues
for(char &c : s) make_uppercase(c);
return move(s); // move s into a returned string object
}
string toupper(string const& s) { // for the rest
// calls the rvalue reference version, by passing
// an rvalue copy.
return toupper(string(s));
}
Now, if you have some rvalue and pass it to toupper, the rvalue can directly be modified, because we know the temporary is a throw-away thing anyway, so we can aswell just change it and don't need to copy it. Also, the same observation is used for the thing called move-constructors and move-assignment. The right hand side is not copied, but its things are just stolen away and moved to *this.
If you were to say that rvalues can bind to non-const lvalue references, then you would have no way to figure out whether that references an lvalue (named object) or an rvalue (temporary) in the end.
It's probably more little know, but useful anyway, you can put lvalue or rvalue ref-qualifiers on a member function. Here is an example, which naturally extends the existing semantics of rvalue references to the implicit object parameter:
struct string {
string& operator=(string const& other) & { /* ... */ }
};
Now, you can't anymore say
string() = "hello";
Which is confusing and is not really making sense most of the time. What the & above does is saying that the assignment operator can only be invoked on lvalues. The same can be done for rvalues, by putting &&.
Because adding a new kind of reference allows you to write two overloads of a method:
void CopyFrom(MyClass &&c)
{
dataMember.swap(c);
}
void CopyFrom(const MyClass &c)
{
dataMember.copyTheHardWay(c);
}
The version that accepts the new kind of reference is allowed to modify the variable it receives, because that variable isn't going to be used anywhere else. So it can "steal" the contents of it.
This is the whole reason this feature was added; retaining one type of reference wouldn't achieve the desired goal.