当我正在学习C ++ 11 rvalue引用并移动语义时,我开始对函数如何返回一个值来初始化变量感到困惑。请看以下示例:
Widget makeWidget()
{
Widget w;
…
return w;
}
Widget w1 = makeWidget();
这里我假设没有RVO(即编译不会复制/移动)。执行return语句return w;
时,执行函数:
1)复制初始化一个临时对象,其值成为函数的返回值,在一个众所周知的位置(一些固定的寄存器或调用者知道的内存位置)?然后调用者提取此对象以复制初始化w1
?或者
2)该函数获取调用者传递的内存位置w1
,函数的自动变量w
用于复制初始化{{1} }? (这是某种类型的RVO吗?还是某种内联函数行为?或者它是一种可能的调用约定?)
如果是第一种情况,并且return创建一个临时的,则会有两个复制构造函数调用,一个创建临时调用,一个创建w1
。如果是第二种情况,则只有一个复制构造函数调用来创建w1
。
现在假设我们有RVO。然后,如果return的行为是case 1),那么编译器可以通过直接在众所周知的位置构造w1
来获得返回值,从而忽略临时的复制结构。如果返回的行为类似于 2),那么在这种情况下,RVO甚至可以直接在为w
分配的内存位置创建自动变量w
。我对RVO的理解是否正确?
现在让我添加移动语义。再次假设没有RVO,请看下面的例子:
w1
现在再次针对上述两种情况:
1)我预计会有两个动作:第一步来自初始化带有表达式Widget makeWidget()
{
Widget w;
…
return std::move(w);
}
Widget w1 = makeWidget();
的临时Widget
对象;第二步是使用临时值std::move(w)
初始化w1
? OR
2)只有一个步骤:使用表达式Widget
初始化w1
?
最后一个问题:返回行为是否取决于它是返回POD类型还是类类型?
答案 0 :(得分:6)
1)复制初始化一个临时对象,其值变为 函数的返回值,在一个众所周知的位置(一些固定的寄存器 或来电者知道的内存位置)?然后调用者获取此对象 复制初始化w1?
大概这个。通常,调用者分配必要的堆栈空间来保存返回值,并将指针作为隐藏参数传递给它。
请注意,两个复制初始化实际上都是移动。
然后编译器可以忽略临时的构造 直接在众所周知的位置构建
w
以获得返回值。
对(但这是一个举动)。并且它可以通过将其地址作为应该构造返回值的位置来进一步忽略w1
的构造。
Widget makeWidget() { Widget w; … return std::move(w); } Widget w1 = makeWidget();
这是一个不可移动的行动(从std::move(w)
到临时返回值)和一个可移动的移动(从临时返回值到w1
)。
返回行为取决于它是返回POD类型还是返回 班级类型?
它可以。根据平台ABI,可以在寄存器中返回一些小的POD类型。