我正在尝试理解右值引用和移动语义。在下面的代码中,当我将 10 传递给 Print 函数时,它会调用右值引用重载,这是预期的。但究竟会发生什么,这 10 会被复制到哪里(或者从它引用的地方)。其次,
std::move
实际上是做什么的?它是否从 i
中提取值 10 然后传递它?或者它指示编译器使用右值引用?
void Print(int& i)
{
cout<<"L Value reference "<<endl;
}
void Print(int&& i)
{
cout<<"R Value reference "<< endl;
}
int main()
{
int i = 10;
Print(i); //OK, understandable
Print(10); //will 10 is not getting copied? So where it will stored
Print(std::move(i)); //what does move exactly do
return 0;
}
谢谢。
但是到底发生了什么,这 10 个将在哪里被复制(或从它引用的地方)
创建一个临时值,并将引用传递给函数。临时变量是rvalues,因此可以绑定到rvalue引用;所以选择第二个重载。
其次
实际上做了什么?std::move
它为您提供了对其参数的rvalue引用。它相当于(根据定义)
static_cast<T&&>
。
尽管有这个名字,它本身并不做任何运动;它只是为您提供一个可用于移动值的参考。
在
10
的情况下,可能会涉及优化,这会改变实际的实现,但从概念上讲,会发生以下情况:
创建临时
int
并使用值 10
进行初始化。临时
int
绑定到 r 值参考函数参数。因此从概念上讲,没有复制 - 引用将指的是临时的。
至于
std::move()
:可能存在一些与引用等相关的棘手位,但原则上,它只是到右值引用的转换。 std::move()
实际上不移动任何东西。它只是将其参数转换为右值,以便可以将其移出。
无论如何,“移动”并不是一个真正定义的操作。虽然考虑移动很方便,但重要的是左值与右值的区别。
“移动”通常由移动构造函数、移动赋值运算符和采用右值引用的函数(例如
push_back()
)来实现。正是它们的实现使移动成为实际的移动 - 也就是说,它们的实现使得它们可以“窃取”r 值的资源而不是复制它们。这是因为,作为右值,它将不再可访问(或者你向编译器保证)。
这就是为什么
std::move()
启用“移动” - 它将其参数转换为右值,发出信号,“嘿,编译器,我不会再使用这个左值了,你可以让函数(例如移动向量)将其视为 r 值并从中窃取。”
std::move
通过 int
将 int&&
投射到 static_cast<int&&>
中。
最终,如果类型是 class
或 struct
,则将调用移动构造函数(如果已定义(隐式或显式)),而不是调用 copy constructor
/classical constructor
。