为什么 std::move() 中的 static_cast 擦除参数的值?
Why does static_cast in the std::move() wipe value of argument?
我的问题包含两部分:
函数 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
为什么这样的代码:
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 等)
我的问题包含两部分:
函数
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
为什么这样的代码:
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 tonullptr
or 0 all data instring
object. Whilestd::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 等)