【问题标题】:Why does static_cast in the std::move() wipe value of argument?为什么 std::move() 中的 static_cast 会擦除参数的值?
【发布时间】:2021-10-07 04:04:07
【问题描述】:

我的问题包含两个部分:

  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 =之后使用了字符串的move构造函数。它必须通过将字符串对象中的所有数据等同于nullptr 或 0 来擦除初始字符串。而std::move() 本身只返回右值。对吗?

我知道我的问题与 static_cast to r-value references and std::move change their argument in an initialization 类似,但我没有找到明确的解释。

【问题讨论】:

  • 改变s1的不是std::movestatic_cast,而是用于初始化s2string(string&amp;&amp;)构造函数。这是移动语义的重点。自己看看——如果你只是单独写std::move(s1);s1 将保持不变。

标签: c++ rvalue static-cast stdmove


【解决方案1】:

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

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

对吗?

是的,你没看错。基本上就是这样。

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

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

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

...用其他使用移动语义的内容构造字符串。 other 处于有效但未指定的状态。

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

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

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

【讨论】:

  • 关于默认移动构造函数的一个小问题:他是只将 std::move() 应用于每个字段还是将旧指针也等同于 nullptr?
  • @MaxPopovsky 移动后的对象保证为空或nullptr
【解决方案2】:
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() 返回对右值实体的新引用(右值引用),即使初始实体是左值。它是通过使用通用引用Tp&amp;&amp; 作为输入参数来实现的@ 最后。

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

所以,std::move() 返回一个对右值实体的新引用,因此根据上面列出的推理,这个右值引用被认为是一个右值实体。因此 std::move() 的结果可能会作为右值参数输入到适当的构造函数或函数中。相应地,为了改变它所引用的实体的引用能力,我们可以改变初始实体,即使它是一个左值(设置为零 ptr 等)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-07
    • 2014-02-16
    • 2018-04-17
    • 1970-01-01
    • 2021-08-17
    • 2020-05-25
    • 1970-01-01
    相关资源
    最近更新 更多