上一篇:C++箴言:理解Terminology术语 >>
C++箴言:只要有可能就推迟变量定义
| 天极软件专题专区精选 到天极软件“读编交流区”畅所欲言 | |||
| Google专区 | POPO专区 | QQ专区 QQ挂机 | 了解Web2.0 |
| Flash MX 视频教程 | Photoshop视频教程 | 网页设计视频教程 | 照片处理数字暗房 |
| PPT动画演示教程 | Excel动画教程集 | Word动画演示教程 | Windows Vista专区 |
| 特洛伊木马专区 | 黑客知识教程专区 | 防火墙应用专区 | 注册表应用专区 |
| Windows API开发专区 | 网络编程专区 | VB数据库编程专区 | 图像处理与多媒体编程 |
在极大程度上,为你的类(包括类模板)和函数(包括函数模板)提供正确的定义是战斗的关键性部分。一旦你得到正确的结果,相应的实现很大程度上就是直截了当的。但是仍然有一些注意事项需要当心。过早地定义变量会对性能产生拖累。过度使用强制转换会导致缓慢的,难以维护的,被微妙的 bug 困扰的代码。返回一个类内部构件的句柄会破坏封装并将空悬句柄留给客户。疏忽了对异常产生的影响的考虑会导致资源的泄漏和数据结构的破坏。过分内联化(inlining)会导致代码膨胀。过度的耦合会导致令人无法接受的漫长的建构时间。 这一切问题都可以避免。
只要有可能就推迟变量定义
只要你定义了一个带有构造函数和析构函数的类型的变量,当控制流程到达变量定义的时候会使你担负构造成本,而当变量离开作用域的时候会使你担负析构成本。如果有无用变量造成这一成本,你就要尽你所能去避免它。
你可能认为你从来不会定义无用的变量,但是也许你应该再想一想。考虑下面这个函数,只要 password 的长度满足要求,它就返回一个 password 的加密版本。如果 password 太短,函数就会抛出一个定义在标准 C++ 库中的 logic_error 类型的异常(参见 Item 54):
| // this function defines the variable "encrypted" too soon std::string encryptPassword(const std::string& password) { using namespace std; string encrypted; if (password.length() < MinimumPasswordLength) { throw logic_error("Password is too short"); } ... // do whatever is necessary to place an // encrypted version of password in encrypted return encrypted; } |
对象 encrypted 在这个函数中并不是完全无用,但是如果抛出了一个异常,它就是无用的。换句话说,即使 encryptPassword 抛出一个异常,你也要为构造和析构 encrypted 付出代价。因此得出以下结论:你最好将 encrypted 的定义推迟到你确信你真的需要它的时候:
| // this function postpones encrypted’s definition until it’s truly necessary std::string encryptPassword(const std::string& password) { using namespace std; if (password.length() < MinimumPasswordLength) { throw logic_error("Password is too short"); } string encrypted; ... // do whatever is necessary to place an // encrypted version of password in encrypted return encrypted; } |
这一代码仍然没有达到它本可以达到的那样紧凑,因为定义 encrypted 的时候没有任何初始化参数。这就意味着很多情况下将使用它的缺省构造函数,对于一个对象你首先应该做的就是给它一些值,这经常可以通过赋值来完成我已经解释了为什么缺省构造(default-constructing)一个对象然后赋值给它比用你真正需要它持有的值初始化它更低效。那个分析也适用于此。例如,假设 encryptPassword 的核心部分是在这个函数中完成的:
| void encrypt(std::string& s); // encrypts s in place |
那么,encryptPassword 就可以这样实现,即使它还不是最好的方法:
| // this function postpones encrypted’s definition until // it’s necessary, but it’s still needlessly inefficient std::string encryptPassword(const std::string& password) { ... // check length as above std::string encrypted; // default-construct encrypted encrypted = password; // assign to encrypted encrypt(encrypted); return encrypted; } |
一个更可取得方法是用 password 初始化 encrypted,从而跳过毫无意义并可能很昂贵的缺省构造:
| // finally, the best way to define and initialize encrypted std::string encryptPassword(const std::string& password) { ... // check length std::string encrypted(password); // define and initialize // via copy constructor encrypt(encrypted); return encrypted; } |
这个建议就是本 Item 的标题中的“只要有可能(as long as possible)”的真正含义。你不仅应该推迟一个变量的定义直到你不得不用它之前的最后一刻,而且应该试图推迟它的定义直到你得到了它的初始化参数。通过这样的做法,你可以避免构造和析构无用对象,而且还可以避免不必要的缺省构造。更进一步,通过在它们的含义已经非常明确的上下文中初始化它们,有助于对变量的作用文档化。
“但是对于循环会如何?”你可能会有这样的疑问。如果一个变量仅仅在一个循环内使用,是循环外面定义它并在每次循环迭代时赋值给它更好一些,还是在循环内部定义这个变量更好一些呢?也就是说,下面这两个大致的结构中哪个更好一些?
| // Approach A: define outside loop // Approach B: define inside loop Widget w; for (int i = 0; i < n; ++i){ for (int i = 0; i < n; ++i) { w = some value dependent on i; Widget w(some value dependent on i); ... ... } } |
这里我将一个类型 string 的对象换成了一个类型 Widget 的对象,以避免对这个对象的构造、析构或赋值操作的成本的任何已有的预见。
对于 Widget 的操作而言,就是下面这两个方法的成本:
方法 A:1 个构造函数 + 1 个析构函数 + n 个赋值。
方法 B:n 个构造函数 + n 个析构函数。
对于那些赋值的成本低于一个构造函数/析构函数对的成本的类,方法 A 通常更高效。特别是在 n 变得很大的情况下。否则,方法 B 可能更好一些。此外,方法 A 与方法 B 相比,使得名字 w 在一个较大的区域(包含循环的那个区域)内均可见,这可能会破坏程序的易理解性和可维护性。因此得出以下结论:除非你确信以下两点:(1)赋值比构造函数/析构函数对成本更低,而且(2)你正在涉及你的代码中的性能敏感的部分,否则,你应该默认使用方法 B。
Things to Remember
·只要有可能就推迟变量定义。这样可以增加程序的清晰度并提高程序的性能。
下一篇:C++箴言:将强制转型减到最少 >>
相关文章:
- · Google推电邮安全软件 杀除病毒和间谍件
- · 我国软件业扶持指挥棒变向 欲抓大放小
- · 美三大信息产业协会访华 推销技术路线图
- · 是帐号就黑 密码解霸变种W太过疯狂
- · 微软7.75亿美元结束与IBM十年纠纷
- · 鲍尔默访华双重厚礼:62亿大单
- · IBM、微软之庭外和解的前因后果
- · 微软发布IE安全公告 黑客可运行任意代码
- · 微软发布IE安全公告 黑客可运行任意代码
- · Sun微软历史性握手 服务器预装Windows
- · 微软人才招聘遇寒冬 人事政策受抨击
- · 杜绝安全隐患 容易忽视的Oracle安全问题
- · 微软发布桌面版Live 三巨头激烈圈地
- · 微软称系统中毒后很难修复 重装才是正解
- · 微软要求英PC商停售裸机 开源社区反对
- · 微软看好Web2.0 将提供people ready
- · 微软打造两款新搜索产品挑战Google
- · 挪威政府欲戒微软瘾 扩大使用开源软件
- · 微软测试新邮件系统 年底发布最终版本
- · 域名注册商转向Windows 微软蚕食Apache
- · 微软欧盟本月对簿公堂 争论创新和产权
- · 方正与微软签采购协议 3年超2.5亿美金
- · Win98 7月终止支持 微软提醒用户升级
- · 微软定价之谜:每套可能跌破100元
- · IBM将在DB2数据库中采用新压缩存储技术
- · IBM新DB2数据压缩到每一行可省50%磁盘
- · 法官认为SCO证据不足 IBM取阶段性胜利
- · 国产人工智能搜索出世 扬言淘汰Google
- · 微软高层盛赞开源软件并发放3D技术许可证
- · Linux Journal特别供稿:别了,微软
- · 消息人士透露微软将遭欧盟2到3亿欧元罚款
- · 软件奇人叫板盖茨 1万美元打赌Vista跳票
- · 遭客户反对 微软删除Windows隐私文件夹
- · 鲍尔默称XP和Vista间隔太长 不犯类似错误
- · 微软和雅虎IM互通的启示意义
- · Web2.0时代的人本营销
- · Web2.0继续蔓延 个人思想渗入企业软件
- · Web2.0公司所要做的就是撕掉Web2.0标签
