Effective C++ 26-30 Note
条款26:尽可能延后变量定义式的出现时间
等到出现有意义值时再定义,避免无意义的默认构造函数(习惯使用拷贝构造函数)
条款27:尽量少做转型动作
C++提供的四种新式转型方法
宁可使用新式转型,也不要使用旧式转型。前者很容易辨别出来,而且也比较有着分门别类的职掌
如果可以,尽量避免转型,特别是在重视效率的代码中避免dynamic_casts
dynamic_cast用于将一个基类转换为派生类,之所以需要它,是因为你想在一个你认为是派生类的基类对象中使用派生类函数。
可以在基类中提供一个”什么也不做“的virtual函数,让派生类继承的时候实现它。根据动态绑定即可通过基类对象调用派生类版本的函数。
如果转型是必要的,试着将它隐藏于某个函数背后。客户随后可以调用该函数,而不需将转型放在他们自己的代码内
条款28:避免返回handles(号码牌,用来取得某个对象)指向对象内部成分
避免返回handles(包括references、指针、迭代器)指向对象内部。遵守这个条款可增加封装性,帮助const成员函数的行为像个const,并将发生”虚吊号牌(dangling handles)“的可能性降至最低
当const成员函数返回引用时,用户可以根据返回的引用修改成员的值,这样的行为与函数的const签名不符
通过对象的成员函数获取到指向对象数据的引用,这个引用会随着对象的消除而变成”虚吊状态“。(对象消除了,指向对象成员的引用还保留着)
条款29:为”异常安全“而努力是值得的
当异常被抛出时,带有异常安全性的函数会:
1、不泄露资源:是否有new出来的指针没有被delete
2、不允许数据败坏:在构造函数执行时发生异常,其中的一些变量已经成功初始化但另一些变量没有
异常安全函数可以按照提供的保障分成三种类型:基本型、强烈型、不抛异常型
”强烈保证“往往能够以 copy-and-swap 实现出来,但”强烈保证“并非对所有函数都可实现或具备现实意义
获得本对象资源的一个副本,在副本上进行修改,将修改后的副本和原资源进行swap。
在效率问题上,每进行一次改动,都要提供一个”副本“。这会导致额外的开销
函数提供的”异常安全保证“通常最高只等于其所调用之各个函数的”异常安全保证“中的最弱者
条款30:透彻了解inlining的里里外外
不要只因为function template出现在头文件,就将它们声明为inline
将大多数inlining限制在小型、被频繁调用的函数身上。
inline函数会在每一次调用的时候都将以函数本体替换之,这会增加目标码的大小。在一台内存有限的机器上,过度热衷inlining会造成程序体积太大。
inline只是对编译器的一个申请,不是强制命令,编译器可以加以忽略
通过函数指针调用inline函数,该调用或许不被inline
类的构造函数或析构函数往往是inlining的糟糕人选:虽然有时候构造函数拥有空函数体,但为了完成对象初始化,编译器会隐式地产生相应的代码加到构造函数里面。所以虽然看上去构造函数是空的,实际上它含有很多代码,不适合声明为inline