Reputation: 5167
The description for static cast says
If new_type is an rvalue reference type, static_cast converts the value of expression to xvalue. This type of static_cast is used to implement move semantics in std::move.(since C++11)
Does this confirm that the following are equivalent ?
(A)
X x1;
X x2 = static_cast<X&&>(x1);
(B)
X x1;
X x2 = std::move(x1);
Upvotes: 32
Views: 10692
Reputation: 1193
They are not strictly equivalent. std::move()
's implementation relies on static_cast
:
template<typename _Tp>
constexpr typename std::remove_reference<_Tp>::type&&
move(_Tp&& __t) noexcept
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); }
They differ in the sense that std::move()
has remove_reference
to deal with reference collapse. An example where (A) and (B) are not strictly equivalent:
// Set up different behavior for lvalue and rvalue.
class T {};
void func(T&& t) { std::cout << "rvalue captured.\n"; }
void func(T& t) { std::cout << "lvalue captured.\n"; }
// Example:
Using X = T&;
X x1;
X x2 = static_cast<X&&>(x1); // (A) "lvalue captured."
X x3 = std::move(x1); // (B) "rvalue captured."
Upvotes: 2
Reputation: 5665
In C++11, T&&
is an rvalue reference. They behave like lvalue references from C++ 98/03. Their goal - to be a candidate for moving. In C++98 this construct can appear in reference collapsing.
std::move
- turn expression into an rvalue. It could have been called rvalue_cast, but wasn't.
Explicit cast to type T&&
is possible in principle. The official standard costs some money, but in the ISO/IEC 14882:2011 draft there's this:
5.2.9 Static cast
8)
The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) conversions are applied to the operand....
From a practical point of view, it is more convenient to use std::move
.
Consider this example:
#include <stdio.h>
#include <utility>
class A
{
public:
A () {printf ("A ()" "\n");}
A (const A &) {printf ("A (&)" "\n");}
A (A &&) {printf ("A (&&)" "\n");}
A (const A &&) {printf ("A (const &&)" "\n");}
~ A () {printf ("~ A ()" "\n");}
};
int main ()
{
const A obj;
A obj2 (std::move (obj)); // 1-st approach
A obj3 (static_cast <const A&&> (obj)); // 2-nd approach
}
For me, the first approach is:
static_cast
to const A&&
, or to A&&
?)std::move
in the project)Upvotes: 4
Reputation: 269
You can use static_cast<A &&>(a)
when a is an rvalue, but you shouldn't use std::move(a)
.
When you use A && a = std::move(A())
, you get a dangling reference.
The basic idea is that the lifetime of a temporary cannot be further extended by "passing it on": a second reference, initialized from the reference to which the temporary was bound, does not affect its lifetime.
std::move
's implementation is somewhat like
template <typename T>
constexpr decltype(auto) move(T && __t) noexcept // when used in std::move(A()),
// the lifetime of the temporary object is extended by __t
{
return static_cast<typename std::remove_reference<T>::type &&>(__t); // a xvalue returned, no lifetime extension
}
auto && a = std::move(A()); // the anonymous object wiil be destructed right after this line
Upvotes: -3
Reputation: 2767
Yes there is a very important difference: std::move
documents what you want to do. In addition the cast is prone to writing errors like a forgotten &
or wrong type X
.
As it can be seen, std::move
is even less to type.
Upvotes: 45