C++对象模型——暂时性对象 (第六章)

6.3    暂时性对象 (Temporary Objects)

假设有一个函数,形式例如以下:

T operator+(const T &, const T &);

以及两个T objects,a和b,那么:

a + b;

可能会导致一个暂时性对象,以放置传回的对象.是否会导致一个暂时性对象,视编译器的进取性(aggressiveness)以及上述操作发生时的程序上下关系(program context)而定.比如以下这个片段:

T a, b;
T c = a + b;

编译器会产生一个暂时性对象,放置a+b的结果,然后再使用T的copy constructor,把该暂时性对象当作c的初值.然而更好的转换则是直接以拷贝构造的方式,将a+b的值放到c中,于是就不须要暂时性对象,以及对其constructor和destructor的调用了.

此外,视operator+()的定义而定,named return value(NRV)优化(详见2.3节)也可能实施起来.这将导致直接在上述c对象中求表达式结果,避免运行copy constructor和具名对象(named object)的destructor.

三种方式所获得的c对象,结果都一样.其间的差异在于初始化的成本.一个编译器可能给不论什么保证吗?严格来说没有,C++ Standard同意编译器对于暂时性对象的产生有全然的自由度.

但实际上,差点儿不论什么表达式假设有这样的形式:

T c = a + b;

当中的加法运算符被定义为:

T operator+(const T &, const T &);

T T::operator+(const T &);

那么实现时根本不产生一个暂时性对象.

然而注意,意义相当的assignment语句:

c = a + b;

    不可以忽略暂时性对象.

所以这种初始化操作:

T c = a + b;

总是比以下的操作更有效率地被编译器转换:

c = a + b;

第三种运算形式是,没有出现目标对象:

a + b;    // no target

这时候有必要产生一个暂时对象,以放置运算后的结果.尽管看起来有点怪异,但这样的情况实际上在子表达式中十分普遍.比如,假设这样写:

String s("hello"), t("world"), u("!");

那么不论:

String v;
v = s + t + u;

printf("%s\n", s + t);

都会产生一个暂时对象,与s + t相关联.

最后一个表达式带来了一个论题,那就是"暂时对象的生命周期".

一种比較被喜欢的转换方式是在调用printf()之后实施String destructor.在C++ Standard下,这正是该表达式的必须转换方式.标准规格这样将:

暂时性对象的被摧毁,应该是对完整表达式求值过程中的最后一个步骤,该表达式造成暂时对象的产生.

什么是一个完整表达式?非正式地说,它是被涵括的表达式中最外围的那个.以下这个表达式:

// tertiary full expression with 5 sub-expressions
((objA > 1024) && (objB > 1024)) ?

objA + objB : foo(objA, objB);

一种有五个子表达式,内带在一个"?:完毕表达式"中.不论什么一个子表达式所产生的不论什么一个暂时对象,都应该在完整表达式被求值完毕后,才干够销毁.

当暂时性对象是依据程序的运行期语意有条件地被产生出来时,暂时性对象的生命规则就显得有些复杂了.举个样例,想这种表达式:

if (s + t || u + v)

当中的u+v子算式仅仅有在s+t被评估为 false 时,才会開始被评估.与第二个子算式有关的暂时性对象必须被销毁.可是,非常显然地,不能够被无条件地销毁.也就是说,希望仅仅有在暂时性对象被产生出来的情况下才去销毁它.(假设第一个子算式为 true,则不产生第二个暂时性对象,不须要销毁)

把暂时性对象的destructor放在每个子算式的求值过程中,能够免除"努力追踪第二个子算式是否真的须要被评估".然而在C++ Standard的暂时对象生命规则中,这种策略不再被同意.暂时性对象在完整表达式尚未评估全然之前,不得被销毁.也就是说,某些形式的条件測试如今必须被插入进来,以决定是否要晓辉何第二算式有关的暂时对象.

    暂时对象的生命规则有两个例外.第一个例外发生在表达式被用来初始化一个object时.比如:

bool verbose;
...
String progNameVersion = !verbose ? 0 : progName + progVersion;

当中progName和progVersion都是String objects.这时候会生出一个暂时对象,放置加法运算符的运算结果:

String operator+(const String &, const String &);

暂时对象必须依据对verbose的測试结果有条件地解构.在暂时对象的生命规则下,它应该在完整的"?

:表达式"结束评估后尽快被销毁.然而,假设progNameVersion的初始化须要一个copy constructor:

progNameVersion.String::String(temp);

那么暂时性对象的解构(在"?

:完整表达式"之后)当然那就不是期望的.C++ Standard要求:

...凡是含有表达式运行结果的暂时性对象,应该存留到object的初始化操作完毕为止.

暂时性对象的生命规则的第二个例外是"当一个暂时性对象被一个reference绑定"时,比如:

const String &space = " ";

产生出这种程序代码:

// C++ pseudo Code
String temp;
temp.String::String(" ");
const String &space = temp;

非常明显,假设暂时性对象如今被销毁,那个reference也就没实用了.所以C++ Standard要求:

假设一个暂时性对象被绑定在一个reference,对象将残留,直到被初始化的reference的生命结束,或直到暂时对象的生命范畴(scope)结束--视哪一种情况先到达而定.

暂时性对象的迷思

有一种说法是,因为当前的C++编译器会产生暂时性对象,导致程序的运行比較没有效率.

时间: 2024-12-30 10:36:42

C++对象模型——暂时性对象 (第六章)的相关文章

C++对象模型——临时性对象 (第六章)

6.3    临时性对象 (Temporary Objects) 如果有一个函数,形式如下: T operator+(const T &, const T &); 以及两个T objects,a和b,那么: a + b; 可能会导致一个临时性对象,以放置传回的对象.是否会导致一个临时性对象,视编译器的进取性(aggressiveness)以及上述操作发生时的程序上下关系(program context)而定.例如下面这个片段: T a, b; T c = a + b; 编译器会产生一个临时

第六章、数据库及数据库对象

第六章.数据库及数据库对象 内容提要: 1.了解数据库的组成及特点 2.掌握SQL Server2008的安装与配置 3.掌握数据库的创建及维护方法 4.掌握架构的定义与维护方法 5.掌握分区表.索引及视图的创建及维护方法 第一节.创建及维护数据库 1.1.SQL Server数据库概述 SQL Server的发展史 SQL Server 7.0(1999年,正式跻身企业数据库行列) SQL Server 2000(2000年,代表产品) SQL Server 2005(2005年,代号"Yuk

第六章:异常机制

第六章:异常机制 异常的定义 异常:在程序运行过程中出现的意外事件,导致程序中断执行. 异常处理 try...catch 语法:try{ //可能出现异常的代码}catch(异常类型 异常对象名){ //处理异常的代码:}执行过程:当try中的代码异常发生时抛出一个异常对象,该异常对象与catch中异常类型进行匹配,匹配成功进入catch块,否则不执行catch中代码(相当于异常未被处理).程序只有当异常处理成功后才能继续执行. try...catch...catch 语法:try{ //可能出

ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第六章:管理产品图片:多对多关系(上)

这章介绍了怎样创建一个新的实体来管理图片,怎样使用HTML窗体来上传图片文件和使用多对多关系来使它们与产品相关,并且怎样来保存图片到文件系统中.这章也介绍了更多复杂的错误处理增加客户端错误到模型中为了把它们显示回给用户.在这章中播种数据库使用的产品图片可能在在第六章的从Apress网页站点下载代码中. 注意:如果你想遵从这章的代码,你必须完成第五章的代码或者从www.apress.com下载第五章的源代码作为一个起点. 创建实体保存图片文件名 这个项目,我们正要使用文件系统在Web项目中存储图片

大道至简第六章

今天看了看大道至简第六章<从编程到工程>.文章以<列子·说符>的“得其精而忘其粗,在其内而忘其外:见其所见,不见其所不见,视其所视,而遗其所不视.”为题记.第一节讲了“语言只是工具”,作者讲述了他曾经对一些编程语言的看法.他曾经也热衷于讨论语言的优劣,但是他现在不这样了,他已经不再专注于语言, 正如他在第一章中写到的一样:成天讨论这门语言好,或者那门语言坏的人,甚至是可悲的.确实,程序的好坏不在于语言,在于算法.第二节 说点什么呢,今天看了看大道至简第六章<从编程到工程>

第六章,使用Internet资源的一个问题

今天第六章里的示例代码,运行不起来.提示没有引用的对象. 添附代码片段 private void refreshEarthquakes() {    // Get the XML    URL url;    try {      String quakeFeed = getString(R.string.quake_feed);      url = new URL(quakeFeed); URLConnection connection;      connection = url.open

《Entity Framework 6 Recipes》中文翻译系列 (30) ------ 第六章 继承与建模高级应用之多对多关联

翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章  继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章将帮助你解决许多常见的.复杂的建模问题,并解决你可能在现实中遇到的建模问题. 本章以多对多关系开始,这个类型的关系,无论是在现存系统还是新项目的建模中都非常普遍.接下来,我们会了解自引用关系,并探索获取嵌套对象图的各种策略.最后,本章以继承的高级建模和实体条件结束. 6-1  获取多对多关联中的链接表 问题

C语言笔记(谭版 第六章~末)

第六章       利用数组批量处理数据 数组是一组有序数据的集合,数组中的每一个元素都属于同一数据类型. 算是一种数据的组织结构.初现结构端倪. 一维数组 定义: 类型符 数组名[常量表达式]  数组名命名遵行标示符命名规则 C语言中不允许对数组的大小作动态定义. 说明:如果在被调用函数中定义数组,其长度可以是变量或非常量表达式.实参.此情况称为可变长数组.若数组指定为静态存储方式,此方式不合法. 引用: 数组名[下标] 下标是常量或常量表达式   序号从0开始计起. 初始化:初始化列表  i

锋利jQuery 学习整理之 第六章 jQuery 与Ajax 的应用

1.Ajax 的XMLHttpRequest 对象 XMLHttpRequest 是Ajax 的核心,它是Ajax 实现的关键---发送异步请求.接受响应及执行回调都是通过它来完成的.XMLHttpRequest最早是在Microsoft Internet Explorer  5.0  ActiveX 组件中被引用的. 2.JQuery 中的Ajax jQuery 对Ajax 进行了封装,在jQuery中$.ajax()方法属于最底层的方法,第二层是load().$.load()和$.post(