我想知道NRVO是否在我正在进行的项目中是活跃的(这是Qt,使用MSVC 2013 64位)。
所以我写了这段代码:
class foo
{
public:
foo(){qDebug() << "foo::foo";}
foo(const foo& c){(void)c;qDebug() << "foo::foo( const foo& )\n";}
~foo(){qDebug() << "foo::~foo";}
};
foo bar()
{
foo local_foo;
return (local_foo);
}
void func()
{
foo f = bar();
}
它给了我以下输出:
foo :: foo
FOO ::〜富
我上面提到的链接需要:
FOO :: foo的()
foo :: foo(const foo&amp;)
FOO ::〜FOO()
FOO ::〜FOO()
但是当我用
替换吧台foo f = foo(bar())
然后我获得链接所具有的相同输出。
所以这是我的问题:为什么“foo f = bar()”不会调用复制构造函数?它是否会调用operator =而在调用之前,f是原始存储? (那么为什么2004年的链接行为不一样)? 所以我必须得出结论,NRVO没有打开,对吗?
答案 0 :(得分:3)
为什么&#34; foo f = bar()&#34;不要调用复制构造函数?
因为允许编译器elide复制。
它是否会调用operator =,而在调用之前,f是原始存储?
没有
那么为什么来自2004年的链接的行为方式不同
据推测,他们使用了另一个编译器,编译器的另一个版本或编译器的其他设置,他们的编译器没有删除副本。
所以我必须得出结论,NRVO没有开启,对吧?
从第一个输入中您可以得出结论NRVO 已打开。从第二个输出,您可以得出结论,有一个副本没有被省略。但是,由于打印的副本数量少于没有NRVO的副本,因此您可以断定NRVO已打开,但未应用于所有副本。
&#34; foo f = bar()&#34;之间有什么区别?和foo f = foo(bar())&#34;然后?
第一个副本 - 从f
bar()
第二个显式地使用复制构造函数构造一个临时对象,然后从该临时对象复制初始化f
。两个副本都可以省略。
答案 1 :(得分:1)
允许编译器删除副本。它可以确定本地foo
将超出范围,因此不是在foo
中创建bar
,而是复制它可以将对象直接构造到f
。
所以我必须得出结论,NRVO没有开启,对吧?
没有。这意味着它已打开。
foo f = foo(bar())
对任何体面的优化编译器应该具有相同的效果。运行
class foo
{
public:
foo(){std::cout << "foo::foo\n";}
foo(const foo& ){std:: cout << "foo::foo( const foo& )\n";}
~foo(){std::cout << "foo::~foo\n";}
};
foo bar()
{
foo local_foo;
return (local_foo);
}
int main()
{
foo a = bar();
foo b = foo(bar());
}
我们得到了
foo::foo
foo::foo
foo::~foo
foo::~foo
这表明两个副本都可以优化为一个结构。