C++ return语句是否为按值返回的函数创建临时对象?
在学习C++11右值引用和移动语义时,我开始对函数如何返回值来初始化变量感到困惑。请看以下示例:C++ return语句是否为按值返回的函数创建临时对象?,c++,c++11,C++,C++11,在学习C++11右值引用和移动语义时,我开始对函数如何返回值来初始化变量感到困惑。请看以下示例: Widget makeWidget() { Widget w; … return w; } Widget w1 = makeWidget(); Widget makeWidget() { Widget w; … return std::move(w); } Widget w1 = makeWidget(); 这里我假设没有RVO(即编译不会省略复制
Widget makeWidget()
{
Widget w;
…
return w;
}
Widget w1 = makeWidget();
Widget makeWidget()
{
Widget w;
…
return std::move(w);
}
Widget w1 = makeWidget();
这里我假设没有RVO(即编译不会省略复制/移动)。执行return语句时returnw代码>,功能是否:
1)复制初始化一个临时对象,该对象的值成为函数的返回值,位于一个已知位置(调用方知道的某个固定寄存器或内存位置)?然后调用方获取该对象以复制初始化w1
?或
2)函数获取调用方传递的w1
内存位置,函数的自动变量w
用于复制初始化w1
?(这是否已经是某种RVO?或者某种内联函数行为?或者它是一种可能的调用约定?)
如果是第一种情况,并且return创建一个临时的,那么将有两个复制构造函数调用,一个创建临时的,一个创建w1
。如果是第二种情况,则只有一个复制构造函数调用来创建w1
现在假设我们有RVO。然后,如果返回的行为是case1),那么编译器可以通过直接在已知的返回值位置构造w
来省略临时的复制构造。如果return的行为类似于case2),那么在这种情况下,RVO甚至可以直接在为w1
分配的内存位置中创建自动变量w
。我对RVO的理解正确吗
现在让我添加移动语义。再次假设没有RVO,并查看以下示例:
Widget makeWidget()
{
Widget w;
…
return w;
}
Widget w1 = makeWidget();
Widget makeWidget()
{
Widget w;
…
return std::move(w);
}
Widget w1 = makeWidget();
现在再次针对上述两种情况:
1)我是否希望有两个移动:第一个移动来自使用表达式std::move(w)
初始化tempWidget
对象;第二步是使用tempWidget
初始化w1
,这是一个右值?或
2)只有一个移动:使用表达式std::move(w)
初始化w1
最后一个问题:返回行为是否取决于它返回的是POD类型还是类类型
1) 复制初始化临时对象,其值将成为
函数的返回值,位于已知位置(某些固定寄存器
或者调用方知道的内存位置)?然后调用者获取这个对象
复制初始化w1
大致如此。通常,调用方分配必要的堆栈空间来保存返回值,并将指向该值的指针作为隐藏参数传递
请注意,这两个副本初始化实际上都是移动
然后,编译器可以通过
直接在已知位置构造w
以获取返回值
对(但这是一个动作)。它还可以通过将其地址作为应该构造返回值的位置来传递,从而进一步省略w1
的构造
这是一个不可删除的移动(从std::move(w)
到临时返回值)和一个可删除的移动(从临时返回值到w1
)
返回行为是否取决于它返回的是POD类型还是POD类型
班级类型
它可以。根据平台ABI的不同,一些小型POD类型可能会在寄存器中返回。大多数编译器的调用约定是,调用者传入指向原始空间的指针,函数在其中构造返回值。至少在效率最低的情况下(根本没有RVO),临时副本是从该空间中的w
构建的,然后w1
是从该临时副本构建的副本。大多数编译器都会省略其中一个或两个副本,后者通过将分配给w1
的空间传递给函数,从而将返回值直接构造到w1
中;前者通过使w
成为同一空间的别名,实际上使w
和w1
引用同一对象。