The C++11 std::move(x)
function doesn't really move anything at all. It is just a cast to r-value. Why was this done? Isn't this misleading?
相关问题
- Sorting 3 numbers without branching [closed]
- How to compile C++ code in GDB?
- Why does const allow implicit conversion of refere
- thread_local variables initialization
- What uses more memory in c++? An 2 ints or 2 funct
相关文章
- Class layout in C++: Why are members sometimes ord
- How to mock methods return object with deleted cop
- Which is the best way to multiply a large and spar
- C++ default constructor does not initialize pointe
- Selecting only the first few characters in a strin
- What exactly do pointers store? (C++)
- Converting glm::lookat matrix to quaternion and ba
- What is the correct way to declare and use a FILE
It is correct that
std::move(x)
is just a cast to rvalue - more specifically to an xvalue, as opposed to a prvalue. And it is also true that having a cast namedmove
sometimes confuses people. However the intent of this naming is not to confuse, but rather to make your code more readable.The history of
move
dates back to the original move proposal in 2002. This paper first introduces the rvalue reference, and then shows how to write a more efficientstd::swap
:One has to recall that at this point in history, the only thing that "
&&
" could possibly mean was logical and. No one was familiar with rvalue references, nor of the implications of casting an lvalue to an rvalue (while not making a copy asstatic_cast<T>(t)
would do). So readers of this code would naturally think:Note also that
swap
is really just a stand-in for all kinds of permutation-modifying algorithms. This discussion is much, much bigger thanswap
.Then the proposal introduces syntax sugar which replaces the
static_cast<T&&>
with something more readable that conveys not the precise what, but rather the why:I.e.
move
is just syntax sugar forstatic_cast<T&&>
, and now the code is quite suggestive as to why those casts are there: to enable move semantics!One must understand that in the context of history, few people at this point really understood the intimate connection between rvalues and move semantics (though the paper tries to explain that as well):
If at the time
swap
was instead presented like this:Then people would have looked at that and said:
The main point:
As it was, using
move
, no one ever asked:As the years went on and the proposal was refined, the notions of lvalue and rvalue were refined into the value categories we have today:
(image shamelessly stolen from dirkgently)
And so today, if we wanted
swap
to precisely say what it is doing, instead of why, it should look more like:And the question everyone should be asking themselves is if the above code is more or less readable than:
Or even the original:
In any event, the journeyman C++ programmer should know that under the hood of
move
, nothing more is going on than a cast. And the beginner C++ programmer, at least withmove
, will be informed that the intent is to move from the rhs, as opposed to copy from the rhs, even if they don't understand exactly how that is accomplished.Additionally, if a programmer desires this functionality under another name,
std::move
possesses no monopoly on this functionality, and there is no non-portable language magic involved in its implementation. For example if one wanted to codeset_value_category_to_xvalue
, and use that instead, it is trivial to do so:In C++14 it gets even more concise:
So if you are so inclined, decorate your
static_cast<T&&>
however you think best, and perhaps you will end up developing a new best practice (C++ is constantly evolving).So what does
move
do in terms of generated object code?Consider this
test
:Compiled with
clang++ -std=c++14 test.cpp -O3 -S
, this produces this object code:Now if the test is changed to:
There is absolutely no change at all in the object code. One can generalize this result to: For trivially movable objects,
std::move
has no impact.Now lets look at this example:
This generates:
If you run
__ZN1XaSERKS_
throughc++filt
it produces:X::operator=(X const&)
. No surprise here. Now if the test is changed to:Then there is still no change whatsoever in the generated object code.
std::move
has done nothing but castj
to an rvalue, and then that rvalueX
binds to the copy assignment operator ofX
.Now lets add a move assignment operator to
X
:Now the object code does change:
Running
__ZN1XaSEOS_
throughc++filt
reveals thatX::operator=(X&&)
is being called instead ofX::operator=(X const&)
.And that's all there is to
std::move
! It completely disappears at run time. Its only impact is at compile-time where it might alter what overload gets called.Let me just leave here a quote from the C++11 FAQ written by B. Stroustrup, which is a direct answer to OP's question:
By the way, I really enjoyed the FAQ - it's worth reading.