NRV RVO

来源:互联网 发布:淘宝全景图怎么做 编辑:程序博客网 时间:2024/05/16 12:07

[C++] C++疑问?关于copy constructor? [复制链接]
00

lc1999

丰衣足食

Rank: 1

帖子
879
主题
449
精华
1
可用积分
982
专家积分
0
在线时间
230 小时
注册时间
2003-02-12
最后登录
2012-02-16
  • 问答
  • 好友
  • 博客
  • 消息
论坛徽章:
0
跳转到指定楼层
1楼[收藏(0)][报告]
 发表于 2005-08-31 05:40:46 |只看该作者 |倒序浏览
  1. #include <iostream>;
  2. using namespace std;

  3. class X {
  4. public:
  5.   X()         throw();
  6.   X(const X&) throw();
  7. };

  8. X::X()         throw() { cout << "default constructor\n"; }
  9. X::X(const X&) throw() { cout << "copy constructor\n";    }

  10. X userCode(X b) throw()                     
  11. {
  12.   X c = b;                                        
  13.   return c;
  14. }                                                    

  15. int main()
  16. {
  17.   X a;
  18.   cout << "calling userCode()\n";
  19.   X d = userCode(a);
  20.   cout << "back in main()\n";
  21. }
复制代码


以上代码,书上的输出如下:

default constructor
calling userCode()
copy constructor 
copy constructor 
copy constructor 
back in main()


我在windows下用g++,输出如下:

default constructor
calling userCode()
copy constructor 
copy constructor 
back in main()

少了一次copy  constructor调用。
我发现是这个语句 X d = userCode(a);没有调用copy constructor。



难道是书上错了?Addison.Wesley.Cpp.FAQs.2nd.Edition


谢谢!



C++疑问?关于copy constructor?

编译器的优化所致。

如果没有任何优化,拷贝构造函数应该被调用 4 次:
  • 函数实参 a 和虚参 b 结合时
  • 函数内 c 创建并用 b 来初始化时
  • 函数返回时创建临时对象并用 c 来初始化时
  • 对象 d 创建并用函数返回的临时对象初始化时


一般的编译器都可以做到返回值优化(Return Value Optimization, RVO),即直接把返回值建立在函数返回值要初始化或者赋值的对象上(上例中的对象 d)。这个优化的目的是消除函数返回时的临时对象的创建以及拷贝。这样优化之后上面的程序就只有 3 次拷贝了(上表中的 3 被省略,d 变为由 c 直接初始化拷贝),也就是上面书上给出的结果。

在此基础上编译器还可以进行进一步的优化:有名返回值优化(Named Return Value Optimization, NRVO)。NRVO 指的是:如果函数中 return 的对象是一个局部变量且为非 const 或 volatile,编译器可以把这个局部变量(上例中的对象 c)直接建立在函数返回值要初始化或者赋值的对象上(上例中的对象 d)。这样优化之后就只有 2 次对象拷贝操作了(上表中的 3、4 被省略)。

至于这种优化为什么叫“有名”返回值优化,那是因为它优化的对象是函数返回的局部变量,而这个局部变量是有名子的(Named)。与之对应,上面提到的 RVO 是对函数返回临时对象的优化,而这个临时对象是一个无名对象。

0 0