为什么 std::move() 中的 static_cast 擦除参数的值?

Why does static_cast in the std::move() wipe value of argument?

我的问题包含两部分:

  1. 函数 static_cast<Т>(arg) 会改变 arg 的内部结构吗?显然不是,按照这样的代码:

    float i1 = 11.5;
    int x = static_cast<int>(i1);
    std::cout << i1<<std::endl;   //11.5
    std::cout << x<<std::endl;    //11
    
  2. 为什么这样的代码:

    std::string s1 = "123";
    std::string s2 = std::move(s1);
    std::cout << s1 << std::endl;  //empty
    std::cout << s2 << std::endl;  //123
    

    其中 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); }
    

    使 s1 成为一个空字符串?

我猜,是因为在s2 =之后使用了字符串的移动构造函数。它必须通过等于 nullptr 或 0 字符串对象中的所有数据来擦除初始字符串。而 std::move() 本身只返回右值。正确吗?

我知道我的问题与 之类的问题重复,但我没有找到明确的解释。

在阅读您的问题时,我有一种感觉,您已经了解正在发生的事情,但仍希望确认

I guess, it is because of using move constructor of string after s2 =. It must wipe the initial string by equating to nullptr or 0 all data in string object. While std::move() by itself is only returning rvalue.

Is it correct?

是的,你没看错。这基本上就是正在发生的事情。

std::move 不会移动,也不会改变对象的任何状态 “自身”。 它只是将给定对象的类型转换为右值引用。

它是 std::basic_string 的构造函数,在您的示例中消除了 s1

cppreference 中,它简要介绍了它的作用:

...Constructs the string with the contents of other using move semantics. other is left in valid, but unspecified state.

尝试编写这样的示例代码来证明您的观点:

std::string s = "Hello World";
(void)std::move(s); // (void) is there to discard the warning message.
std::cout << s;

您可以看到 s 根本没有改变。

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() returns 对右值实体的新引用(右值引用),即使初始实体是左值。它是通过使用通用引用 Tp&& 作为可以引用左值或右值表达式的输入参数,type_traits 函数 std::remove_reference 从实体中删除所有引用,并将其转换为右值引用来创建的通过在末尾的 static_cast 中添加 && 。

任何引用都只是它所引用的实体的另一个名称,我们可以通过这个引用来改变那个实体。在某些近似中,引用被视为它所引用的对象。

因此,std::move() returns 对右值实体的新引用,因此根据上面列出的推理,此右值引用被视为右值实体。因此 std::move() 的结果可能会像右值参数一样被送入适当的构造函数或函数。并且根据引用能力来改变它所指的实体,我们可以改变初始实体,即使它是一个左值(设置为零 ptr 等)