More Effective C++ 第四部分 效率

Posted zhangqixiang5449

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了More Effective C++ 第四部分 效率相关的知识,希望对你有一定的参考价值。

16.谨记80-20法则

程序80%的时间用在20%的代码上,盲目的优化程序并不会带来性能的显著改善,应该先借助程序分析器寻找那20%的代码,对其实行优化。


17.考虑使用缓式评估(lazy evaluation)

缓式评估更通俗的说法是拖延战术。延缓运算,直到运算结果被迫切的需要为止,这样可以避免一些得到结果却无用的计算。例如标准库的string

String s1 = "HH";
String s2 = s1;

执行了这两个语句后s2并没有复制s1的副本,而只是记录s2与s1共享了字符串HH,因为我们并不一定会改变s2的内容(若只是读s2内容依旧是读共享的字符串),若在第一时间就将s1的copy给s2将可能造成不必要的copy成本。所以直到改变了s2的内容时,才将s1 copy给s2。

缓式取出Lazy Fetching

如果某个对象的内容需要通过网络在数据库中取出,那么可以只取出需要使用的一部分,而不是将整个对象的信息全部取出。
这个对象的内容被初始化为空,在某个成员需要使用的时候才初始化那么成员,这会造成在任何时候都可能对成员赋值,即使是const 函数,使用mutable可以使变量在const函数内改变值;

mutable int* data;

表达式缓评估

书中给出的例子是计算矩阵时并非一开始便计算完成,需要使用其某个结果时便只计算需要的一部分,这样可以大大的提高效率。


18.分期摊还预期的计算成本

超急评估over-eager evaluation

超急评估与缓式评估是相对立的,超急评估指在运行时一直维护某些数据即使某些时候没有用到,这些数据是被经常取用的,其平均成本将比缓式评估低。


19.了解临时对象的来源

临时对象指一个没有命名的non-heap object,通常发生于隐式类型转换和函数返回对象。这些对象的产生和销毁成本可能对程序造成影响。

当函数参数与传入参数类型不符,但可以被转换时,会发生隐式类型转换产生临时对象,除非传递方式是reference-to-non-const。例如

void func(const string& str);

char c[10];
func(c);//会产生string类型临时对象

传递方式是reference-to-non-const时不会产生临时对象进行隐式转换的原因是,程序员期望在原对象是做修改,而非临时对象。 但reference-to-const并不需要修改,因为其const特性,所以可以产生临时对象以便函数调用。

函数返回对象产生的临时对象问题在下一章。


20.协助完成返回值优化(RVO)

有些函数必须以by value方式返回,例如operator*,这种情况不必考虑不以by value方式返回。
避免产生临时对象的返回方式:在return语句构造对象,使编译器可以对其优化

const A operator*(const A& lhs, const A& rhs)
    return A( lhs.num() * rhs.num() );


A a(1);
A b(2);
A c = a * b;

这样写法可以使编译器在c上直接构造,而不是产生一个临时对象在copy给c。


21.利用重载技术避免隐式类型转换

class UPInt
public:
    UPInt(int val);
;

const UPInt operator+(const UPInt& lhs, const UPInt& rhs);

UPInt upi1,upi2
UPInt upi3 = upi1 + upi2;
upi3 = upi1 + 10;//将会创造一个临时对象给10转换为UPInt类型用
upi3 = 10 + upi2;//将会创造一个临时对象给10转换为UPInt类型用

使用重载技术可以避免临时对象的开销:

const UPInt operator+(const UPInt& lhs, int rhs);
const UPInt operator+(int lhs, const UPInt& rhs);
//注意必须有一个参数是自定义类型。

使用重载会使代码量增加,除非这样做会使程序效率有较大的提升,否则应避免这样做。


22.考虑以操作符复合形式(op=)取代其独身形式(op)

复合形式指+=,-=这样的操作符,独身形式即+,-这样的操作符。
以复合形式取代独身形式的方法:

class A
public:
    A& operator+=(const A& rhs);
;
const A operator(const A& lhs, const A& rhs)
    retuen A(lhs) += rhs;//以lhs构造对象(返回值优化,见20),并调用+=

这样做的好处是:
1.复合操作符效率高,因为其将结果直接写入左端变量,而独身操作符需要一个临时对象。
2.减少代码重复,便于维护。


23.考虑使用其他程序库

找出性能的瓶颈在于程序库中的函数,则可以考虑换一个程序库以提高效率,因为一个程序库并不是在任何地方效率都是最佳的。


24.了解virtual function,multiple inheritance,virtuanl base classes,runtime type identification的成本

这章的内容在Inside c++ object model深入理解对象模型一书中有详细的介绍,在我的博客中有这本书的笔记。

以上是关于More Effective C++ 第四部分 效率的主要内容,如果未能解决你的问题,请参考以下文章

More Effective C++ 第三部分 异常

《More Effective C++》总结笔记

More Effective C++ 第六部分 杂项讨论

《More Effective C++》总结笔记——异常

《More Effective C++》阅读笔记

More Effective C++ 第一部分 基础议题