本文章属于专栏- 概述 -《业界C++进阶建议整理》-CSDN博客
本文列出《Effective C++》的21-30条的个人理解的极精简版本。
- 21、在创建一个新对象时,永远不要返回引用
- 在函数中创建对象,无论是栈上对象(会变成悬空引用),还是堆上对象(容易内存泄漏),都不要返回引用
- 注意operator= 并不是返回一个新的对象,其是返回的自身,所以返回*this的引用
- 22、成员变量全用private
- protected并不比public更有封装性
- 个人见解:对于新的程序,可以保持这样的态度。对于维护程序,有时候代码的一致性更加重要,易于维护
- 23、用non-member、non-friend替换member函数
- 个人见解:对于仅调用多个成员函数的函数,用non-member理论上增加了一点封装性(能访问到私用成员变量的函数越少,封装越好),但是non-member函数需要在另一个地方维护(一般用namespace维护),增加了代码阅读的难度,分散了精力
- 24、当所有参数需要类型转换,使用non-member函数
- 对成员函数,const A operator*(const A& a) const;如果A可以由int隐式转换,则 2*a会失败,所以必须是non-member函数const A operator*(const A& lhs, const A& rhs)
- 个人见解:业务应用代码中,放弃2*a这种隐氏转换的逻辑,节约不了多少代码,也没有提升性能的作用。实践中,先转换,再用operator更好
- 25、考虑写一个不抛异常的swap
- 标准库的std::swap是异常安全的。有时候为了性能,需要一个不抛异常的。如代码
template <typename T>
void customSwap(T& a, T& b) noexcept {
T temp = std::move(a);
a = std::move(b);
b = std::move(temp);
}
- 26、尽可能延后变量定义
- 变量的定义是需要耗费资源的,只在使用之前定义,能提高性能
- 个人见解:c语言的习惯是在函数前几行就定义好。但性能不如使用前定义好的,除非编译器优化,但是不要寄托太多的希望在编译器优化上
- 27、尽量少做转型动作
- 转型动作:
- const_cast:唯一有能力把变量从const转为non-const的转型操作符
- dynamic_cast:唯一可能耗费巨大成本的转型动作。
- 基类 -> 派生类,失败返回nullptr
- 派生类 -> 基类,保证成功,和static_cast作用一样
- reinterpret_cast:告诉编译器,对一个内存数据,换一个方式解释。(常用的唯一的用途,是对void*做算术偏移会用到,但也尽量别用)
- static_cast:强迫隐式转换,无法将const转为non-const
- 在c++中,对象的布局方式和它们的地址计算方式随编译器变化而变化。不要猜测对象在c++中如何布局。如Derived d; Base* b = &d; 如果是多继承,有时候b和d的地址一定不一样,单继承不一定,
- static_cast转换后返回新的副本,在派生类的成员函数中调用基类的成员函数,如果用static_cast<D>(*this).fun(),则调用的不是this的fun,而是this的副本的fun,如果fun改变了成员函数,这个用法将出错。这时候应该用B::fun()
- dynamic_cast实现取决于编译器,一个普遍的实现版本是比较class名称的字符串,对于一个四层单继承体系的对象,最多可能调用4次strcmp。
- 对于大多数使用dynamic_cast的场景都可以通过虚函数避免。
- 个人见解:如果要判断基类指针指向的派生类类型,在基类中加一个字段枚举效率更高
- 转型动作:
- 28、避免返回handles(指针、引用、迭代器)指向对象的内部成分
- 防止用户对其进行更改
- 29、为“异常安全”(函数要么成功,要么是调用前的状态)而努力是值得的
- 如有系统有一个函数没有异常安全,那系统就是非异常安全的。
- 个人见解:并不赞同这条。实践中,放弃构建异常安全的c++程序。即使业务代码保持了这一特性,众多的三方库中也不能保证,并且降低了性能。付出收益比太低了。
- 30、透彻了解inline的里里外外
- 在同一个函数调用中,更容易被编译器优化
- inline会使二进制膨胀并不是绝对的,在inline函数本体很小时,编译器产生的二进制可能比函数调用更小
- inline是对编译器的申请,而不是命令。不过大多数编译器,在拒绝时会给出警告信息
- inline是编译期行为
- 个人见解:只对大量占用CPU资源的代码考虑是否inline。执行频率低的代码,是不是inline并不影响全局,把精力花到有价值的事情上。