Quantcast
Channel: CSDN博客推荐文章
Viewing all articles
Browse latest Browse all 35570

深度探索C++对象模型之(九)

$
0
0

 

=====================================================================

如果喜欢,请关注:JellyThink | 思想的果冻

更多原创精彩博文,尽在www.jellythink.com

还可以关注新浪微博:http://weibo.com/u/1887014677

=====================================================================

Named Return Value(实际上就是返回值优化)
当一个函数返回一个对象的实例,一个临时对象被创建并通过拷贝构造函数传回其值。但是在C++标准中,允许省略拷贝构造函数的对象(前提是所有的路径返回相同的对象),这个也是每个C++编译器义不容辞的责任。
有如下的代码:

#include
using namespace std;
 
class TestA
{
public :
     TestA(){cout<< "Constructor" <<endl;}
     ~TestA(){cout<< "Destructor" <<endl;}
 
     TestA( const TestA& test)
     {
          cout<< "Copy Constructor" <<endl;
     }
 }; 
TestA GetTest() 
{
      TestA test;
      return test; 
} 
int main() 
{
      TestA testA; 
      testA = GetTest();
      return 0 ; 
}


函数GetTest获得一个类的对象,在编译器内部,对于函数GetTest的实际处理会是怎么样的?我先前的博客中有写到,调用和不调用Copy Constructor的时机,而现在的GetTest函数现在就是需要调用Copy Constructor的一种情况。输出如下:

Constructor Constructor 
Copy Constructor 
Destructor 
Destructor 
Destructor 
请按任意键继续. . .


在实际运行上述代码的时候,会输出Copy Constructor,是的,调用了Copy Constructor。这样正好符合我之前的博文中所说的那样。函数GetTest对于编译器来说,会被扩展的,如下:

void GetTest(TestA &result) 
{
      TestA test;
      test.TestA::TestA(); //constructor
      // Do something with test object
      // ...      
      result.TestA::TestA(test);
      return ; 
} 


就像上述函数GetTest函数被编译器展开后的样子,所有的路径都返回相同的Named Value,因此编译器可以做自己的优化。直接以result取代Named Return Valued. 是的,编译器是要进行优化的。默认的情况下,visual studio 2010是关闭NRV的,我们可以在项目属性->配置属性->C/C++->优化中是选择禁用的,所有没有进行优化,你可以打开这个开关(/o2),然后编译上述程序,Copy Constructor是不会调用的。这就是编译器的优化,程序输出如下:

Constructor
Constructor
Destructor
Destructor
请按任意键继续. . .


可以看到,实际少的一次Constructor和一次Destructor正好说明在GetTest函数中的那个生成的result少了,没有了对result的生成和析构。现在是有Copy Constructor而被优化掉了,没有被调用,如果没有Copy Consturctor呢?我把上面的Copy Consturctor注释掉。运行结果如下:

Constructor
Constructor
Destructor
Destructor
Destructor
请按任意键继续. . .


使用MinGW进行编译结果如下(即使有了Copy Consturctor也是一样):

Constructor
Constructor
Destructor
Destructor
请按任意键继续. . .

你会感到很惊讶,怎么会不一样呢?
在《深度探索C++对象模型》一书中有说,Copy Constructor的出现激活了C++编译器中的NRV优化,NRV优化并不通过其它的独立的优化工具完成。可见,这样得到的结果和书中所述是有出路的。事实上,即使是没有定义拷贝构造函数和析构函数,而是由编译器产生(在需要时),NRV依然会对程序的效率产生影响。而Visual Studio 2010中少的那次Constructor调用就是默认拷贝构造函数的调用。
在进行大量对象的复制时,NRV能优化程序,提高效率;但是对于NRV带来的副作用,你可以这么想,就比如在Visual Studio 2010中,刚刚那次隐晦的调用Copy Constructor你知道它的调用吗?也就是说编译器觉的合适,就会生成一个默认的构造函数,但是什么是合适的,我现在不知道,我觉得我也应该不知道,就是因为这种不知道,才给我们日后的编程中埋下了隐患。比如:你的类中有一个static变量记录这个对象被拷贝的次数,由于这种隐患,就很可能给程序生成的结果与预期的不一致;同时,因为NRV,构造函数也不会得到调用,而有的时候,我们期望有些在Copy Constructor中的语句能得到调用,但是如果有了NRV,那就不可能了。
所以,最后,需不需要NRV,视你的具体情况而定。

2013/2/4 于东软-大连

=====================================================================

如果喜欢,请关注:JellyThink | 思想的果冻

更多原创精彩博文,尽在www.jellythink.com

还可以关注新浪微博:http://weibo.com/u/1887014677

=====================================================================

 

作者:vipygd 发表于2013-2-4 22:02:34 原文链接
阅读:56 评论:0 查看评论

Viewing all articles
Browse latest Browse all 35570

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>