4

为了理解编译器如何选择类的构造函数,我编写了以下代码:

#include <iostream>

struct Widget
{
    Widget(Widget&& w){std::cout << "Move ctor" << std::endl;}
    Widget(void){std::cout << "Default ctor" << std::endl;}
    Widget(const Widget& w){std::cout << "Copy ctor" << std::endl;}
};

Widget make_widget(void) //helper function
{
    Widget w;
    return w;
}

int main(void)
{
    Widget w(make_widget());
}

根据 Effective Modern C++ 的第 25 项,由于返回值优化,编译器将 w 视为右值引用。所以我期望Widget w(make_widget())调用移动构造函数。但事实并非如此。此外,它只打印

Default

所以我不知道调用了哪个版本的构造函数。然后我也尝试显式返回右值。即,return std::move(w) 。考虑到上述结果,与我的预期相反,它正确调用了移动构造函数,并打印了

Default
Move

看来我正处于右值的迷宫中。请告诉我那里发生了什么。

4

1 回答 1

3

根据 Effective Modern C++ 的第 25 项,w由于返回值优化,编译器将其视为右值引用。

不,我确定作者不是那个意思。RVO 与是否为右值引用无关。两者w中的make_widgetmain都是类型的左值Widget。如果你有一个 type 的变量Widget&&,它的值类别是左值(因为它有一个标识),它的类型是右值引用。

你看到的Default是由于Widget w;里面make_widget()。由于返回值优化,避免了将其复制到win的操作main,因此您什么也看不到。如果您想在没有 RVO 的情况下查看输出,则在使用时传递-fno-elide-constructors给(无法g++使用 VC++ 禁用 RVO ),您会看到

Default (first creation)
Move    (creation of temporary with the move ctor)
Move    (copying of temporary to the one in main)

当您更改return wreturn std::move(w)时,为返回创建的临时是用右值构造的,因此您会在输出中看到一个额外的Move

于 2016-03-02T07:27:11.613 回答