MSCV,构造函数,析构函数和NRVO行为

时间:2016-02-29 13:49:45

标签: c++ c++11

我想知道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没有打开,对吗?

2 个答案:

答案 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());
}

On Coliru

我们得到了

foo::foo
foo::foo
foo::~foo
foo::~foo

这表明两个副本都可以优化为一个结构。