17-考虑使用lazy evaluation(缓式评估)
第三章,异常
条款17 考虑使用lazy evaluation(缓式评估)
(1)尽可能延迟提供副本,COW思想,数据共享(多个指针指向听一片内存,引用计数获取对应数据)
String s1 = "Hellow"; |
(2)读时可以使用refernce-counter思想提效,而写时不得不进行拷贝动作,那如何判断 opertator[] 是读还是写呢?见条款30 proxy classes
String s = "Homer's Iliad"; |
(3)例子: Lazy Fetching(缓式取出)
想象你的程序使用大型对象,其中内含许多字段。
如此对象必须在程序每次执行时保持与前次执行的一致性与连贯性,
所以它们必须存储于一个数据库中。每个对象有一个独一无二的对象识别码,可用来从数据库中取回对象
class LargeObject { // 大型的、可持久存在的(persistent)对象。 |
// 修改 |
(4)例子: Lazy Expression Evaluation(表达式缓评估)
template<class T> |
如果operator + 马上就执行计算,那么消耗的资源势必不少,但是如果延迟到真正使用m3的时候呢?毕竟大部分情况下使用者是希望获取m3中某一行或某一列的计算结果;
要实现这种效果,就需要两个执行要运算的矩阵的指针,和一个enum枚举表明将进行什么运算;
但是有一些情况,如:
1、当要求输出全部计算结果的时
cout << m3; |
2、指针指向内容改变时
m3 = m1 + m2; |
应对这些情况,需要存储数值间的相依关系,而且必须维护一些数据结果以存储数值、相依关系,或者是两者的组合,此外还必须将赋值、复制、加法等操作符加以重载。
那么,这么多工作值得吗?
值得,这样的设计通常能够再程序执行时节省大量的时间和空间,在许多应用领域中有这样的收益是值得的。
总结:
1、避免非必要的对象复制,可区别operator[]的读取和写动作;
2、避免非必要的数据库读取动作
3、避免非必要的数值计算动作
注意:
尽管如此,lazy evaluation并非永远是好主意。因为正如计算数值的例子那样,如果所有计算都是必要的,那么lazy evalution起到的效果几乎没有,且由于为了实现lazy evaluation所做的那些工作会占据不少程序内存,反而可能导致程序更加缓慢。
只有在软件被要求执行某些计算,而那些计算其实可以避免时,lazy evalution才会有用处
引申:
APL就是采用lazy evalution来延缓计算,直到确切知道其结果矩阵在哪一部分被真正需要,就只做这一部分的计算;正是这样的伎俩支撑起了APL这个诞生于古老的20世纪60年代的神奇。
