静态转换为右值引用和std :: move之间有什么区别吗?

时间:2013-06-17 07:14:33

标签: c++ c++11 move static-cast

静态演员的描述

  

如果new_type是右值引用类型,static_cast会将expression的值转换为xvalue。这种类型的static_cast用于在std :: move中实现移动语义。(自C ++ 11起)

这是否确认以下内容相同?

(A)

X x1;
X x2 = static_cast<X&&>(x1); 

(B)

X x1;
X x2 = std::move(x1);

4 个答案:

答案 0 :(得分:32)

是的,有一个非常重要的区别:std::move记录您想要做的事情。此外,演员也容易写出错误的&或错误类型X

可以看出,std::move输入的内容更少。

答案 1 :(得分:1)

T&amp;&amp; 在C ++ 11中是rValue参考。它们的行为类似于C ++ 98,03中的左值引用。他们的目标 - 成为移动的候选人。在C ++ 98中,这种构造可以出现在refrence collapsing

std :: move - 在rvalue中转换表达式。它可以被称为 rvalue_cast ,但这样的关键字不存在。

显式转换为类型T&amp;&amp;原则上是可能的。真正的标准花费了一些钱,但在ISO/IEC 14882:2011的草案中 存在这样的信息

  

5.2.9静态演员

     

8)

     

左值到右值(4.1),数组到指针(4.2)和函数到指针(4.3)的转换应用于   操作数......

从实际的角度来看,使用std :: move更方便。 想象一下这样的例子:

#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
}

至于我的第一种方法是

  • 更方便(你应该执行static_cast到 const A&amp;&amp; ,还是 A&amp;&amp; ?)
  • 更明确(我可以在文本编辑器中使用搜索来查找项目中的std :: move)
  • 软件开发人员编写代码时不易出错

答案 2 :(得分:0)

它们不是严格等效的。 std::move()的实现依赖于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); }

它们的区别在于std::move()remove_reference要处理reference collapse。 (A)和(B)不严格相等的示例:

// 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."

答案 3 :(得分:-2)

当a是左值时,您可以使用static_cast<A &&>(a),但不应使用std::move(a)
当您使用A && a = std::move(A())时,您会获得一个悬空参考。

基本思想是临时的生命周期不能通过“传递”来进一步扩展:第二个引用,从临时绑定的引用初始化,不会影响其生命周期。

std::move的实现有点像

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