设为首页 加入收藏

TOP

13.5 延迟计算
2013-10-07 14:06:20 来源: 作者: 【 】 浏览:67
Tags:13.5 延迟 计算

13.5  延迟计算

为一个最终可能不需要的计算付出性能代价显然不是明智之举。然而在复杂的代码中这种情况比比皆是。我们不应该执行"只在某种情况下"才需要的昂贵计算,而应该只在必要的时候执行昂贵计算。这通常常意味着把计算推迟到真正需要的时候才进行,因此称之为延迟计算(Lazy eva luation)[Mey96, ES90]。

早在纯C程序时代,我们就习惯在程序的开头预先定义所有的变量。而在C++(www.cppentry.com)中,对象的定义会调用构造函数和析构函数,这可能是高成本的,因为它导致了立即计算--而这正是我们所要避免的。延迟计算原则建议我们推迟对象的定义,直到要使用该对象时再定义。为不一定用到的构造函数和析构函数付出代价是没有意义的。这听起来很可笑,实际上却时常发生。

在一个用C++(www.cppentry.com)编写的网关程序中,我们有一段运行在AIX内核的对程序性能至关重要的代码。这段代码用于交换下行和上行通信适配器的消息。在程序定义的对象中,有一个对象的构造和析构函数代价很昂贵:

  1. int route(Message *msg)  
  2. {  
  3.     ExpensiveClass upstream(msg);  
  4.  
  5.     if (goingUpstream) {  
  6.         ... // 处理代价昂贵的对象  
  7.         }  
  8.  
  9.     //此处不使用对象upstream  
  10.  
  11.     return SUCCESS;  

使用upstream对象的代价很高。原先的代码急于在函数开始时构造该对象,而事实上在程序中只有一半的时间,即消息被交换至上行时才使用它,在另一半时间,即消息被交换至下行时根本不使用。对于后一种情况,upstream对象的计算完全是浪费的。更好的办法是在真正需要upstream对象的地方定义它:

  1. int route(Message *msg)  
  2. {  
  3.  
  4.     if (goingUpstream) {  
  5.         ExpensiveClass upstream(msg);  
  6.  
  7.         //处理代价昂贵对象  
  8.         }  
  9.  
  10.     //此处不使用对象upstream  
  11.  
  12.     return SUCCESS;  

在[Mey97]的Item 32中,Meyers阐述了另一条关于延迟计算的重要结论:不仅应该将对象的创建推迟至合适的位置,而且应该直到具备了一个有效创建操作所必需的全部条件后,再创建对象。例如:

  1. void f()  
  2. {  
  3.     string s;           // 1  
  4.     ...  
  5.     char *p = "Message";    // 2  
  6.     ...  
  7.     s = p;              // 3  
  8.     ...  

在语句1中,我们调用默认构造函数String:: String()创建了String对象s,之后在语句3中我们赋予s真实内容。直到执行完语句3,对象s才算真正创建完成,因此这是一种低效的构造。它需要以下操作:

默认的string构造函数--在语句1中。

赋值运算符--在语句3中。

延迟计算原则可以将上述操作缩减为仅调用一次构造函数。我们将String型对象s的构造推迟到已具备必需条件后实现。

  1. void f()  
  2. {  
  3.     char *p = "Message";  
  4.     string s(p); //调用String::String(char*)   
  5.     ...  

通过推迟构造s,我们实现了一步构造--这无疑更为高效。

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇13.6 无用计算 下一篇给C++初学者的50个忠告

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: