Effective c++

powered by github 总结

让自己习惯c++/培养良好的c++习惯??

  1. 视c++为语言联邦??

  2. 尽量以const, enum, inline 替换#define预处理器

  3. 尽可能使用const

  4. 确定对象在被使用前就已经初始化了(尽可能不要定义变量后没有初始化)

谏言

  1. 了解c++默默编写了哪些函数?
  • empty class编译器会为其声明哪些东西: 一个copy构造函数, 一个copy assinment 操作符, 一个析构函数, 默认构造函数. 都是public 和 inline的. (默认构造/析构函数, 拷贝构造函数, 赋值运算符, 取址运算符, 取址运算符const)

    • Empty(){}

    • Empty(const Empty&){}

    • ~Empty(){}

    • A& operator=(const A&){}

    • A* operator&(){}

    • const A* operator&()const{}

  1. 如果不想使用编译器自动生成的函数, 应当明显拒绝

  2. 为多态基类声明virtual 析构函数

  3. 别让异常逃离析构函数??

  4. 绝对不在构造和析构的过程中调用virtual函数(因为类调用从不????)

  5. operator= 返回一个 reference to *this

  6. operator= 中处理 "自我赋值"

  7. 赋值对象时应确保复制"对象内的所有成员变量" 及 "所有 base class 成分"

  8. 以对象管理资源, 资源在构造函数获取, 析构函数释放, 建议使用智能指针, 取得即初始化, RAII

  9. 在资源管理类中小心copy行为(普遍的RAII class copy 行为是: 抑制copy, 引用计数, 深度拷贝, 转移资源所有权啊之类的) ??

  10. 成对使用new和delete

  11. 以独立语句将new的对象存储于智能指针

  12. 让接口容易被正确使用, 不易被误用 促进接口正常使用的办法: 接口一致性, 内置类型的行为兼容, 阻止误用的办法: 建立新类型, 限制类型上的操作, 约束对象, 消除客户的资源管理责任

  13. 设计class犹如设计type, 需要考虑: 对象创建, 销毁, 初始化, 赋值, 值传递, 合法值, 继承关系, 转换, 一般化

  14. 在资源管理类中, 一般而言显示转换会比较安全

  15. 成对使用new和delete时要采用相同的形式, 比如new中使用[], 则delete[], new中不使用[], 则使用delete

  16. 以独立的语句将new的对象存储于智能指针中. 不然可能会被编译器一起优化, 导致难以察觉的资源泄漏. 发生异常时可能会导致资源泄漏.

  17. 让接口容易被正确使用, 不易被误用. 促使正确使用的方法: 接口一致性, 内置类型的行为兼容; 防止被误用的方法: 建立新的类型, 限制类型上的操作, 约束对象值, 消除客户的资源管理责任.

  18. 设计class要考虑很多东西: 对象创建, 销毁, 初始化, 赋值, 值传递, 合法值, 继承关系, 转换, 一般化等

  19. 用pass-by-reference-to-const 替换 pass-by-value 就是传参, 尽量采用 const &的方法, 避免多余的拷贝构造和 对象切割(派生类在拷贝构造时会损失派生部分的内容, 表现为基类的特性)

  20. 必须返回对象时, 不要返回pointer和reference, 注意不要返回一个临时对象.

  21. 将成员变量声明为private, 封装性和一致性, 对读写权限的精确控制

  22. 宁以 non-member, non-friend 替换 member函数 (可以增加封装性, 包裹弹性, 机能扩充性)

  23. 若所有参数 (包括被this指针所指向的隐喻参数) 都要类型转换, 请为此采用non-member 函数

  24. 考虑写一个不抛异常的swap函数

  25. 尽可能延后变量定义式的出现时间 (可以增加程序清晰度并改善程序效率)

  26. 尽量少做类型转换的动作, const_static, dynamic_cast , static_cast, reinterpret_cast

  27. 避免使用handles (包括 引用, 指针, 迭代器) 去指向对象内容 (增加封装性)

  28. 为"异常安全"而努力是值得的, 及时发送异常也不会泄漏资源,或者允许任何数据损坏, 分为三种可能的保证: 基本型, 强烈型, 不抛异常型

  29. 透彻了解inlining的里里外外外, inline 内联函数, 取决于编译器, 大部分编译器拒绝太过复杂的函数作为内联函数来使用. 容易导致代码膨胀, 且内联函数无法随着程序库的升级而升级.

  30. 将文件的编译之间的依赖关系降到最低.如果可以, 尽量以class声明替换class 定义式, 为声明和定义提供不同的头文件.

  31. 确定你的public 继承is-a 关系??

  32. 避免遮掩继承而来的名字, 可以使用using 声明式或转接函数??

  33. 区分接口继承和实现的继承, 在public继承之下, derived class 总是继承 base class 的接口, pure virtual 函数只具体指定接口继承, 非纯 impure virtual 函数具体指定接口继承及缺省实现继承??

  34. 考虑virtual 函数以外的其他选择, 将virtual 函数替换为 "函数指针成员变量", 将继承体系内的vitrual函数替换为另外一个继承体系内的virtual函数

  35. 绝对不重新定义继承而来的non-virtual 函数

  36. 绝对不重新定义继承而来的缺省参数值, 因为缺省参数值是静态绑定的, 而virtual 函数却是动态绑定的.

  37. 通过复合塑模 has-a 或 "根据某物实现出"; 在实现域, 复合意味着is-implemented-in-terms-of

  38. 明智而谨慎地使用private继承. 尽可能使用复合, 当derived class 需要访问protected base class成员, 或需要重新定义继承而来的virtual 函数, 或需要 empty base 最优化时, 才使用private继承

  39. 明智而谨慎地使用多重继承, 多继承比单一继承要复杂, 可能导致新的歧义性, 以及对virtual 继承的需要, 但正确的用途也是有的, 比如 "public 继承某个 interface class" 和 "private 继承某个协助实现的 class"; virtual 继承可以解决多继承下的菱形继承的二义性问题, 但会增加大小, 速度, 初始化赋值的复杂度等成本.

  40. 了解隐式接口和编译器多态. (class 和 templates 都支持接口 interface 和多态); class的接口是以签名为中心的显式的explicit,多态则是通过virtual 函数发生于运行期; template的接口是奠基于有效表达式的隐式implicit, 多态则是通过template具现化和函数重载解析发生于编译期.

  41. [模板] 了解typename 的双重意义, 声明template 类型参数是, 前缀关键字 class 和 typename 的意义完全相同; 请使用关键字 typename 标识嵌套从属类型名称, 但不得在基类列表或成员初值列内以它作为base class 修饰符.

  42. [模板] 学习处理模板化基类的名称.

  43. [模板] 运用成员函数函数模板去接收所有兼容类型生成 可接受所有兼容类型的函数.

  44. [模板] 运用成员函数模板接收所有兼容类型

  45. [模板] 需要类型转换时请为模板定义非成员函数

  46. [模板] 请使用 traits classes 表现类型信息

  47. [模板] 认识template元编程, 可以将工作由运行期转移到编译期, 可以实现早期错误侦测和更高的执行效率.

  48. [new-delete] 了解 new-handler的行为, nothrow new是一个颇具局限的工具, 因为它只使用于内存分配, 后续的构造函数调用还是可能抛出异常的.

  49. [new-delete] 了解new 和 delete的合理替换时机, 为了检测运用错误, 收集动态分配内存之使用统计信息, 增加分配和归还速度, 降低缺省内存管理器带来的空间额外开销, 弥补缺省分配器中的非最佳齐位, 增加相关对象......... 太复杂和绕了

  50. [new-delete] 编写new和delete, 需要固守常规, 涵盖无穷循环, 在其中尝试分配内存, 如果没有办法满足内存需求, 调用new-handler, 有能力处理0 bytes申请.

  51. [new-delete] 写了placement new 也要写 palcement delete

  52. 不要忽视编译器的警告

  53. 让自己熟悉标准程序库

  54. 让自己熟悉boost库, 增加一个 poco库

你可能感兴趣的:(Effective c++)