More Effective C++ 条款19

条款19:理解临时对象的来源

当程序员之间进行交谈时,他们经常把仅仅需要一小段时间的变量称为临时变量。例如在下面这段swap(交换)例程里:

template<class T>

void swap(T& object1, T& object2)

{

  T temp = object1;

  object1 = object2;

  object2 = temp;

}

通常把temp叫做临时变量。不过就C++而言,temp跟本不是临时变量,它只是一个函数的局部对象。

C++中真正的临时对象是看不见的,它们不出现在你的源代码中。建立一个没有命名的非堆(non-heap)对象会产生临时对象。这种未命名的对象通常在两种条件下产生:为了使函数成功调用而进行隐式类型转换和函数返回对象时。理解如何和为什么建立这些临时对象是很重要的,因为构造和释放它们的开销对于程序的性能来说有着不可忽视的影响。

首先考虑为使函数成功调用而建立临时对象这种情况。当传送给函数的对象类型与参数类型不匹配时会产生这种情况。例如一个函数,它用来计算一个字符在字符串中出现的次数:

// 返回chstr中出现的次数

size_t countChar(const string& str, char ch);

 

char buffer[MAX_STRING_LEN];

char c;

 

// 读入到一个字符和字符串中,用setw

// 避免缓存溢出,当读取一个字符串时

cin >> c >> setw(MAX_STRING_LEN) >> buffer;

 

cout << "There are " << countChar(buffer, c)

     << " occurrences of the character " << c

     << " in " << buffer << endl;

看一下countChar的调用。第一个被传送的参数是字符数组,但是对应函数的正被绑定的参数的类型是const string&。仅当消除类型不匹配后,才能成功进行这个调用,你的编译器很乐意替你消除它,方法是建立一个string类型的临时对象。通过以buffer做为参数调用string的构造函数来初始化这个临时对象。countChar的参数str被绑定在这个临时的string对象上。当countChar返回时,临时对象自动释放。

这样的类型转换很方便(尽管很危险-参见条款5),但是从效率的观点来看,临时string对象的构造和释放是不必要的开销。通常有两个方法可以消除它。一种是重新设计你的代码,不让发生这种类型转换。这种方法在条款5中被研究和分析。另一种方法是通过修改软件而不再需要类型转换,条款21讲述了如何去做。

仅当通过传值(by value)方式传递对象或传递常量引用(reference-to-const)参数时,才会发生这些类型转换。当传递一个非常量引用(reference-to-non-const参数对象,就不会发生。考虑一下这个函数:

void uppercasify(string& str);               // str中所有的字符

                                             // 改变成大写

在字符计数的例子里,能够成功传递char数组到countChar中,但是在这里试图用char数组调用upeercasify函数,则不会成功:

char subtleBookPlug[] = "Effective C++";

 

uppercasify(subtleBookPlug);                // 错误!

没有为使调用成功而建立临时对象,为什么呢?

假设建立一个临时对象,那么临时对象将被传递到upeercasify中,其会修改这个临时对象,把它的字符改成大写。但是对subtleBookPlug函数调用的真正参数没有任何影响;仅仅改变了临时从subtleBookPlug生成的string对象。无疑这不是程序员所希望的。程序员传递subtleBookPlug参数到uppercasify函数中,期望修改subtleBookPlug的值。当程序员期望修改非临时对象时,对非常量引用(references-to-non-const)进行的隐式类型转换却修改临时对象。这就是为什么C++语言禁止为非常量引用(reference-to-non-const)产生临时对象。这样非常量引用(reference-to-non-const)参数就不会遇到这种问题。

建立临时对象的第二种环境是函数返回对象时。例如operator+必须返回一个对象,以表示它的两个操作数的和(参见Effective C++ 条款23)。例如给定一个类型Number,这种类型的operator+被这样声明:

const Number operator+(const Number& lhs,

                       const Number& rhs);

这个函数的返回值是临时的,因为它没有被命名;它只是函数的返回值。你必须为每次调用operator+构造和释放这个对象而付出代价。(有关为什么返回值是const的详细解释,参见Effective C++条款21

通常你不想付出这样的开销。对于这种函数,你可以切换到operator=,而避免开销。条款22告诉我们进行这种转换的方法。不过对于大多数返回对象的函数来说,无法切换到不同的函数,从而没有办法避免构造和释放返回值。至少在概念上没有办法避免它。然而概念和现实之间又一个黑暗地带,叫做优化,有时你能以某种方法编写返回对象的函数,以允许你的编译器优化临时对象。这些优化中,最常见和最有效的是返回值优化,这是条款20的内容。

综上所述,临时对象是有开销的,所以你应该尽可能地去除它们,然而更重要的是训练自己寻找可能建立临时对象的地方。在任何时候只要见到常量引用(reference-to-const)参数,就存在建立临时对象而绑定在参数上的可能性。在任何时候只要见到函数返回对象,就会有一个临时对象被建立(以后被释放)。学会寻找这些对象构造,你就能显著地增强透过编译器表面动作而看到其背后开销的能力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内容简介   More Effective C++一书充满了实用性高且掷地铿锵的忠告,为你每天可能面对的问题带来帮助。和其前一本兄弟书籍 Effective C++一样,More Effective C++对每一位以C++为开发工具的程序员而言,都必备读物。   继 Effective C++ 之後,Scott Meyers 於 1996 推出这本「续集」。条款变得比较少,页数倒是多了一些,原因是这次选材比「第一集」更高阶,尤其是第五章。Meyers 将此章命名为技术(Techniques),并明白告诉你,其中都是一些 patterns,例如 virtual ctors、smart pointers、reference counting、proxy classes,double dispatching┅等等。这一章的每个条款篇幅都在 15~30 页之谱,实在让人有「山穷水尽疑无路,柳暗花明又一村」之叹。   虽然出版年代稍嫌久远,本书并没有第二版,原因是当其出版之时(1996),C++ Standard 已经几乎定案,本书即依当时的标准草案而写。其间与现今之 C++ 标准规格几乎相同。可能变化的几个弹性之处,Meyers 也都有所说明与提示。读者可以连结作者提供的网址,看看上下两集的勘误与讨论(数量之多,令人惊恐。幸好多是技术讨论或文字斟酌,并没有什麽重大误失)。 编辑推荐 继 Effective C++ 之後,Scott Meyers 於 1996 推出这本「续集」。条款变得比较少,页数倒是多了一些,原因是这次选材比「第一集」更高阶,尤其是第五章。Meyers 将此章命名为技术(Techniques),并明白告诉你,其中都是一些 patterns,例如 virtual ctors、smart pointers、reference counting、proxy classes,double dispatching┅等等。这一章的每个条款篇幅都在 15~30 页之谱,实在让人有「山穷水尽疑无路,柳暗花明又一村」之叹。 虽然出版年代稍嫌久远,本书并没有第二版,原因是当其出版之时(1996),C++ Standard 已经几乎定案,本书即依当时的标准草案而写。其间与现今之 C++ 标准规格几乎相同。可能变化的几个弹性之处,Meyers 也都有所说明与提示。读者可以连结作者提供的网址,看看上下两集的勘误与讨论(数量之多,令人惊恐。幸好多是技术讨论或文字斟酌,并没有什麽重大误失)。 媒体推荐 书评   这是一本多方面发人深省的 C++ 书籍:不论在你偶尔用到的语言特性上,或是在你自以为十分熟悉的语言特性上。只有深刻了解 C++ 编译器如何解释你的码,你才有可能以 C++ 语言写出稳健强固的软体。本书是协助你获得此等层级之了解过程中,一份极具价值的资源。读过本书之後,我感觉像是浏览了 C++ 程式大师所检阅过的码,并获得许多极具价值的洞见。 - Fred Wild, Vce President of Technology, Advantage Software echnologies   本书内含大量重要的技术,这些技术是撰写优良 C++ 程式所不可或缺的。本书解释如何设计和实作这些观念,以及潜伏在其他某些替代方案中的陷阱。本书亦含晚近加入之 C++ 特性的详细说明。任何人如果想要好好地运用这些新特性,最好买一本并且放在随手可得之处,以备查阅。 - Chrisopher J. Van Wyk, Professor Mahematics and Computer Science, Drew University   这是一本具备工业强度的最佳书籍。对於已经阅读过 Effetive C++ 的人,这是完美的续集。 - Eric Nagler, ++ Instructor and Author, Univesity of California Santa Cruz Extension   More Effective C++ 是一本无微不至而且价值不扉的书籍,是 Scott 第一本书 Effective C++ 的续集。我相信每一位专业的 C++ 软体开发人员都应该读过并记忆 Effective C++ 和 More Effective C++ 两本书内的各种招式,以及其中重要(并且有时候不可思议)的语言面向。我强烈推荐这两本书给软体开发人员、测试人员、管理人员┅,每个人都可以从 Scott 专家级的知识与卓越的表达能力中获益。 - Steve Burkett, Software Consutant 作者简介 作者:(美)迈耶斯 译者:侯捷 作者Scott Meyers,是C++领域公认的权威,并对全球客户提供咨询服务。他是Effective C++ 的作者,C++REPORT的知名专栏作家,全球各技术研讨会上级具号召力的讲师。他于1993年拿到布朗大学的计算机科学博士学位。 目录 译序(侯捷) 目录(Contents) 致谢(Acknowledgments. 中文版略) 导读(Introduction) 001 基础议题(Basics) 009 条款1:仔细区别 pointers 和 references 009 Distinguish between pointers and references 条款2:最好使用 C++ 转型操作符 012 Prefer C++-style casts 条款3:绝对不要以polymorphically(多态)方式来处理数组 016 Never treat arrays polymorphically 条款4:非必要不提供 default constructor 019 Avoid gratuitous default constructors 操作符(Operators) 024 条款5:对定制的型别转换函数保持警觉 024 Be wary of user-defined conversion functions 条款6:区别 increment/decrement 操作符的 前置(prefix)和后置(postfix)型式 031 Distinguish between prefix and postfix forms of increment and decrement operators 条款7:千万不要重载 &&, ||, 和 , 操作符 035 Never overload &&, ||, or , 条款8:了解各种不同意义的 new 和 delete 038 Understand the different meanings of new and delete 异常(Exceptions) 044 条款9:利用 destructors 避免泄漏资源 045 Use destructors to prevent resource leaks 条款10:在 constructors 内阻止资源泄漏(resource leaks) 050 Prevent resource leaks in constructors 条款11:禁止异常(exceptions)流出 destructors 之外 058 Prevent exceptions from leaving destructors 条款12:了解「掷出一个 exception」与「传递一个参数」 或「调用一个虚函数」之间的差异 061 Understand how throwing an exception differs from passing a parameter or calling a virtual function 条款13:以 by reference 方式捕捉 exceptions 068 Catch exceptions by reference 条款14:明智运用 exception specifications 072 Use exception specifications judiciously 条款15:了解异常处理(exception handling)的成本 078 Understand the costs of exception handling 效率(Efficiency) 081 条款16:谨记 80-20 法则 082 Remember the 80-20 rule 条款17:考虑使用 lazy evaluation 085 Consider using lazy evaluation 条款18:分期摊还预期的计算成本 093 Amortize the cost of expected computations 条款19:了解暂时对象的来源 098 Understand the origin of temporary objects 条款20:协助完成「返回值优化(RVO)」 101 Facilitate the return value optimization 条款21:利用重载技术(overload)避免隐式型别转换 105 Overload to avoid implicit type conversions 条款22:考虑以操作符复合型式(op=)取代其独身型式(op)107 Consider using op= instead of stand-alone op 条款23:考虑使用其它程序库 110 Consider alternative libraries 条款24:了解 virtual functions、multiple inheritance、virtual base classes、 runtime type identification 所需的成本 113 Understand the costs of virtual functions, multiple inheritance, virtual base classes, and RTTI 技术(Techniques, Idioms, Pattern) 123 条款25:将 constructor 和 non-member functions 虚化 123 Virtualizing constructors and non-member functions 条款26:限制某个 class 所能产生的对象数量 130 Limiting the number of objects of a class 条款27:要求(或禁止)对象产生于 heap 之中 145 Requiring or prohibiting heap-based objects 条款28:Smart Pointers(智能指针) 159 条款29:Reference counting(引用计数) 183 条款30:Proxy classes(替身类、代理类) 213 条款31:让函数根据一个以上的对象型别来决定如何虚化 228 Making functions virtual with respect to more than one object 杂项讨论(Miscellany) 252 条款32:在未来时态下发展程序 252 Program in the future tense 条款33:将非尾端类(non-leaf classes)设计为 抽象类(abstract classes) 258 Make non-leaf classes abstract 条款34:如何在同一个程序中结合 C++ 和 C 270 Understand how to combine C++ and C in the same program 条款35:让自己习惯于标准 C++ 语言 277 Familiarize yourself with the language standard 推荐书目 285 auto_ptr 实现代码 291 索引1(General Index) 295 索引2(Index of Example Classes, Functions, and Templtes) 313

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值