This code does compile but I'm just beginning studying C++11 and I can't understand what's happening here behind the scenes.
void func(int&& var)
{
int var2(var);
}
void main()
{
int var1 = 22;
func(move(var1));
}
My guess: move(var1) returns a r-value of var1 (probably its data) and the func function is initializing var2 with the r-value of var1. But why is var1 still valid after the func call? Shouldn't it have an invalid value because its temp value has been re-assigned to var2?
There are several issues here.
One is that you're working with an int
. And for an int
a copy is just as fast as a move. So it's perfectly reasonable for a move to be implemented as a copy.
There is no requirement that move construction (or assignment) alter the value of the thing being moved from. It's a logical error in your code to continue to treat it as if it had a useful value, but it's not required that the value become useless.
The second is that your code as written doesn't actually move anything. Simply using ::std::move
does not result in something being moved. It's just a nice way to turn an lvalue into an rvalue so that something can be moved. In your case, var
has a name, so it's an lvalue. Your initialization of var2
in func
is actually a copy, not a move. If you had written it int var2(move(var));
it would then be a move and var1
in main
would be potentially invalidated at that point.
To reiterate, the ::std::move
function is just there to signal to people reading your code that a move may happen and that the value of the variable after that cannot be counted on. It doesn't actually move anything.
Here is a marked up version of your code:
// func requires a temporary argument, something that can be moved from
void func(int&& var)
{
int var2(var); // Doesn't actually call int(int &&), calls int(int &)
// int var2(move(var)); // Would actually call int(int &&) and a move would
// happen then at this point and potentially alter the
// value of what var is referencing (which is var1
// in this code).
}
void main()
{
int var1 = 22;
func(move(var1)); // Tell people that var1's value may be unspecified after
// Also, turn var1 into a temporary to satisfy func's
// signature.
}
Since your code, as written, does not result in any moves happening, here is a version that does definitely move something somewhere:
#include <vector>
#include <utility>
using ::std;
// Still require an rvalue (aka a temporary) argument.
void func(vector<int>&& var)
{
// But, of course, inside the function var has a name, and is thus an lvalue.
// So use ::std::move again to turn it into an rvalue.
vector<int> var2(move(var));
// Poof, now whetever var was referencing no longer has the value it used to.
// Whatever value it had has been moved into var2.
}
int main()
{
vector<int> var1 = { 32, 23, 66, 12 };
func(move(var1)); // After this call, var1's value may no longer be useful.
// And, in fact, with this code, it will likely end up being an empty
// vector<int>.
}
And, of course, this way of writing it is silly. There are sometimes reasons to specify that an argument be a temporary. And that's usually if you have one version of a function that takes a reference, and another that takes an rvalue reference. But generally you don't do that. So, here's the idiomatic way to write this code:
#include <vector>
#include <utility>
using ::std;
// You just want a local variable that you can mess with without altering the
// value in the caller. If the caller wants to move, that should be the caller's
// choice, not yours.
void func(vector<int> var)
{
// You could create var2 here and move var into it, but since var is a
// local variable already, why bother?
}
int main()
{
vector<int> var1 = { 32, 23, 66, 12 };
func(move(var1)); // The move now does actually happen right here when
// constructing the argument to func and var1's value
// will change.
}
Of course, giving a name to var1
in that code is kind of silly. Really, it should just be written this way:
func(vector<int>{ {32, 23, 66, 12} });
Then you're just constructing a temporary vector right there and passing it into func
. No explicit use of move
required.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With