随笔-5  评论-31  文章-0  trackbacks-0
题目二:
   题目我做了下改变,使用了上篇文章中提到的那个类X,代码如下:

 1 class X
 2 {
 3 public:
 4     X(){cout<<"default construct"<<endl;}
 5     X(int a):i(a){ cout<<"construct "<<i<<endl;}
 6     ~X(){ cout<<"desconstruct "<<i<<endl;}
 7     X(const X& x):i(x.i)
 8     {
 9         cout<<"copy construct "<<i<<endl;
10     }
11     X& operator++()
12     {
13         cout<<"operator ++(pre) "<<i<<endl;
14         ++i;
15         return *this;
16     }
17     const X operator++(int)
18     {
19         cout<<"operator ++(post) "<<i<<endl;
20         X x(*this);
21         ++i;
22         return x;
23     }
24     X& operator=(int m)
25     {
26         cout<<"operator =(int)"<<endl;
27         i = m;
28         return *this;
29     }
30     X& operator=(const X& x)
31     {
32         cout<<"operator =(X)"<<endl;
33         i=x.i;
34         return *this;
35     }
36     /////////////////////////
37     friend ostream& operator<<(ostream& os,const X& x)
38     {
39         os<<x.i;
40         return os;
41     }
42     friend X operator+(const X& a,const X& b)
43     {
44         cout<<"operator +"<<endl;
45         return X(a.i+b.i);
46     }
47     //////////////////////////
48 public:
49     int i;
50 };

请问以下代码的输出是什么?

1 X a(10),b(20);
2 X c=a+b;

我们来看一下使用GCC4.5(默认编译选项)以及MSVC9.0(BOTH DEBUG AND RELEASE)编译后的实际运行结果:
construct 10
construct 20
operator +
construct 30
desconstruct 30
desconstruct 20
desconstruct 10

简单分析下这个输出:

construct 10 
construct 20 //对应 X a(10),b(20);
operator +  //调用“+”操作符
construct 30 //调用X(int){...},44行处
desconstruct 30 //变量c 的析构
desconstruct 20 //变量b 的析构
desconstruct 10 //变量a 的析构
 从结果可以看出,整个执行过程中没有输出“operator=”,说明压根没有调用“=”操作符,而且整个过程比我想象的要简洁高效,没有临时对象,没有拷贝构造。
结果为什么会是这样呢?这主要归功于编译器的返回值优化的能力。
有关返回值优化的知识,限于篇幅我就不仔细介绍了,但是需要特别指出的是MSVC9.0只在RELEASE模式下默认开启NRVO,即对具名对象的返回值优化,以及返回值优化里面的一个重要的细节,体现在本例里就是:为什么中整个输出中没有出现"opeartor=",即为什么没调用"="操作符。

现在我们将代码稍微改变一下,改成下面的样子:

X a(10),b(20),c;
c
=a+b;  //这里我们将c的构造和赋值分开了

执行的结果如下:

construct 10 //构造a
construct 20 //构造b
default construct //构造 c
operator +  //调用“+”操作符
construct 30 //调用X(int){...},44行处
operator =(X) //调用“=”操作符
desconstruct 30 //代码45行所建立的临时对象的析构
desconstruct 30 //变量c的析构
desconstruct 20 //变量b的析构
desconstruct 10 //变量c的析构

对比前后的输出结果,可以发现多出以下三行
default construct 
operator =(X) 
desconstruct 30 
出现这种差异的原因在于:
定义c的时候会调用默认的构造函数进行初始化,因此第一条语句执行完之后,c已经是一个存在的对象,所以第二条语句并没有权利去直接修改c的内容,必须要通过调用赋值操作符”=“,因此必须要产生一个临时对象。而在第一个例子中,因为执行到第二条语句之前c并没有被创建,所以编译器可以将 表达式a+b的返回值直接构建在c的内存中,从而优化掉临时对象和对“=”的调用。
posted on 2011-08-13 21:38 江浸月 阅读(2070) 评论(7)  编辑 收藏 引用

评论:
# re: 做MTK笔试的总结(二)--C++ 返回值优化(RVO) 2011-08-13 22:32 | 疯狂的面包
楼主我觉得这个问题就像
a = (++a) + (a++);
标准没有规定 在a++ 执行完之后 a马上改变吧;只可以保证在这条语句执行完之后,保证a已经改变。  回复  更多评论
  
# re: 做MTK笔试的总结(二)--C++ 返回值优化(RVO) 2011-08-13 22:48 | 江浸月
@疯狂的面包
没明白你想表达什么。。能再说明白点么。。  回复  更多评论
  
# re: 做MTK笔试的总结(二)--C++ 返回值优化(RVO) 2011-08-13 23:18 | 疯狂的面包
简单来说 楼主Google一下 顺序点  回复  更多评论
  
# re: 做MTK笔试的总结(二)--C++ 返回值优化(RVO) 2011-08-13 23:28 | 疯狂的面包
给楼主你一个链接 http://blog.csdn.net/luciferisnotsatan/article/details/6456696
自己看好 别纠结  回复  更多评论
  
# re: 做MTK笔试的总结(二)--C++ 返回值优化(RVO) 2011-08-14 00:03 | 江浸月
@疯狂的面包
首先谢谢你的链接,让我又学到了些。其次,我没纠结,谢谢。
这题是一套笔试题里的一个题,对于题目的答案我很不确定,我只是抱着实践的态度上机试验,并查阅了相关资料了以后,记录下心得而已。  回复  更多评论
  
# re: 做MTK笔试的总结(二)--C++ 返回值优化(RVO) 2011-08-14 19:49 | ybsunok
X c= a+b;
编译器优化 构造函数,复制构造过程,并不是必须的吧。编译器相关。
  回复  更多评论
  
# re: 做MTK笔试的总结(二)--C++ 返回值优化(RVO) 2011-08-15 15:57 | 水星家纺
编译器优化 构造函数,复制构造过程,并不是必须的吧  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理