[C++] NRV优化

来源:互联网 发布:51单片机spi通信 编辑:程序博客网 时间:2024/05/16 17:50

昨天,室友发给我一个程序让我运行,代码如下:

#include <iostream>#include <string>using namespace std;class Trans {public:Trans() : a(12) {};Trans(int id) : a(0), i(id) {};~Trans() {cout << "good bye " << i << endl;}friend std::ostream& operator<<(ostream&, const Trans&);friend Trans operator + (const Trans&, const Trans&);private:int a;int i;};std::ostream& operator<<(ostream& os, const Trans& tra){return os << tra.a << endl;}Trans operator + (const Trans& t1, const Trans& t2){Trans t(3);t.a = t1.a + t2.a;return t;}int main(){Trans p(1), q(2);cout << p + q;return 0;}

我的运行结果是这样的:


然后将执行结果截图给室友看,室友说跟它的执行结果不一样,他的执行结果在0的前面多了一个good bye 3。这里就不给截图了。

首先说明,我用的GCC,室友用的是VS。同样的程序在不同的编译器下的执行结果不一样,那么,只有一种解释:编译器在幕后给你干了一些事情。

我想到了《深度探索C++对象模型》中的NRV(Named Return Value)优化。

对于函数:

Trans operator + (const Trans& t1, const Trans& t2){Trans t(3);t.a = t1.a + t2.a;return t;}

编译器会将它转换为类似这样:

void operator +(Trans *this, const Trans& t1, const Trans& t2, Trans &__result){    Trans t(3);t.a = t1.a + t2.a;__result(t);return;}

以上的代码在变量和函数名上并没有像编译器一样进行转换,这里只关注编译器是如何返回对象的。

如果编译器采用NVR优化,代码就会被转换成类似这样:

void operator +(Trans *this, const Trans& t1, const Trans& t2, Trans &__result){    __result.Trans::Trans(3);__result.a = t1.a + t2.a;return;}

因此,如果不采用NVR优化,在返回一个对象时,会再创建一个临时对象用于获取返回值,因此,此函数会产生两个对象,如果采用NVR优化,在返回一个对象时,直接用返回值去取代函数内部的局部对象,此时,函数只产生一个对象。所以,对于VS和GCC的不同,或许(这只是我的一种解释这种行为的想法)可以理解为VS没有采用NVR优化,所以会有两个对象析构,而GCC采用了NVR优化,所以只有一个对象被析构。


参考资料:

深度探索C++对象模型,66页,在编译器层面做优化。

1 0