本文章属于专栏《业界Cpp进阶建议整理》
继续上一篇《More Effective C++》- 极精简版 1-10条。本章我会继续讲解我对11-20条的极精简的理解。
- 11、不要让destructor的异常流出
- 先保障不会抛出异常,如果不能,就使用try catch,这里的注意catch里面不再抛出异常也需要人来保证
- 12、抛出一个exception VS 传递一个参数 VS 一个虚函数之间的差异
- 异常机制的个人见解:异常机制核心收益是减少了用户对三方库的理解成本。在业务代码中使用try-catch包住异常,以让三方库的异常在有限的范围内,并且业务代码的函数执行状态由返回值表示。如果记不住繁琐的异常机制,记住我说的这个原则就够了。
- 调用函数时,控制权会回到调用端,但是异常不会
- exception objects总是被复制,如果以by value捕获,会被复制两次
- throw 的exception对象,使用的静态类型,而不是动态类型
- catch子句,会在第一次匹配成功时执行
- 虚函数总是找到最匹配的,而不是第一个匹配的
- 13、以by reference方式捕捉exceptions
- by point要担心当前point是否可用
- by value有复制成本
- 14、明智使用excpetion specification
- 个人见解:这个规则已经不适合c++11及之后的版本。忘记它,考虑第12条中我给出的建议
- 15、异常处理的成本
- exception是c++的一部分,即使你从未使用,只要有一个依赖库用了,就有了一些成本。如果不要,需要对编译器明确禁止
- 整体try语句快,代码膨胀5%-10%,速度下降5%-10%
- exception成本较高,但是它出现的频率是极低的,比正常情况慢3个数量级。
- 注意,这个性能的变换,more effective cpp的作者也是根据部分测试结果来判断的,它很难推断,而是需要测试验证。
- 16、80-20法则
- 用性能测试工具找到性能瓶颈,然后花80%的精力优化20%
- 17、缓式评估
- 写时复制,如String s1 = "a"; String b = "a",编译器可能会只有在b使用时,才进行真正的复制。这也是变量定义贴近使用句子的道理
- 区分读写,cout << a[0]为读,a[0] = 'a'为写。operator并不能区分,但是通过proxy class可以做到(30条)
- 个人见解:核心思想是,等到确定真正要用的时候才做计算。它并不能减少需要计算数据的计算量,而是尽量不做不需要结果的计算
- 如矩阵的class operator* 并不是真正的相乘,而是记录所需信息。而是在operator[],才真正的做计算
- 18、分期摊还预期的计算成本
- 当预期部分数据被频繁需要时,提前计算。如vector每次预分配的内存,是当前的两倍
- 19、了解临时对象的来源
- 临时变量不是局部变量,临时变量并没有名字
- 两种来源:隐式转换作为函数参数、函数返回对象时
- char* a = (str_ + "end").c_str(); a指向了一个临时对象(注意不是局部变量),随时可能改变
- 20、协助完成“返回值优化”
- 个人见解:在现代C++中,函数返回对象时,编译器会先尝试使用RVO,不行会先考虑使用移动构造函数,最后才是拷贝构造函数。所以,对于c++的默认对象或者小对象,直接返回,编译器会帮助用户只拷贝一次,对于大的对象建议还是在栈上申请,通过指针传递
下一篇:《More Effective C++》- 极精简版 21-30条