提高编程效率的C++编程箴言

版权声明:阅读优秀源码,宛若一场探索未知的旅行,疑惑处惊奇,优雅处旖旎; 一切都是新奇的,千回百转与大师的心灵触碰,一场跨越时空的对话,涤荡了原有的愚昧,蜕变出更好的自己。 https://blog.csdn.net/FENGQIYUNRAN/article/details/26510181
  1. 对于单纯常量,最好以const对象或enums替换#defines
  2. 对于形似函数的宏,最好改用inline函数替换#define
  3. 将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
  4. 当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。
  5. 确定对象被使用前已经被初始化。
  6. 为内置型对象手工初始化,因为C++不保证初始化它们。
  7. 构造函数最好使用成员初始列,而不要在构造函数内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中生命的的次序相同。
  8. 为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象。
  9. 编译器可以按自为class创建default构造函数、copy构造函数、copy assignment 操作符,以及析构函数。
  10. 若不想使用编译器的自动生成函数,就该明确拒绝;为驳回编译器自动提供的机能,可将成员函数声明为private并且不予实现。使用像uncopyable这样的base class也是一种做法。
  11. 带多态性质的基类应该声明一个virtual析构函数。如果类带有任何virtual函数,他就应该拥有一个virtual析构函数。
  12. 类的设计目的如果是作为基类使用,或不是为了具备多态性质,就不该声明virtual析构函数。
  13. 析构函数绝对不要吐出异常。如果一个被戏构函数调用的函数可能抛出异常,析构函数应该能捕捉任何异常,然后吞下他们或结束程序。
  14. 如果客户需要对某个操作运行期间抛出异常做出反应,那么class应该提供一个普通函数(而不是在析构函数中)执行该操作。
  15. 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至继承类。
  16. 确保当对象自我赋值时operator=有良好的行为。其中技术包括比较“来源对象”和“目标对象”的地址、精心周到的语句顺序、以及copy-and-swap。
  17. 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。
  18. 复制对象时不要忘记每一个成分。
  19. 复制函数应该确保复制“对象内的所有成员变量”及所有基类成分。
  20. 不要尝试以某个复制函数实现另一个复制函数。应该将共同机能放进第三个函数中,并由两个coping函数共同调用。
  21. 为了避免资源泄露,获得资源后应立刻放进管理对象内;管理对象运用析构函数确保资源被释放。
  22. 两个经常被使用的RAII是tr1::shared_ptr和auto_ptr。前者通常是较佳的选择,因为其copy行为比较直观。若选择auto_ptr,复制动作会使它指向null。
  23. 复制RAII必须一并复制它所管理的资源,所以资源的coping行为决定RAII对象的coping行为。
  24. 常见的RAII:一直coping、施行引用计数法。
  25. APIs往往要求访问原始资源,所以每一个RAII应该提供一个“取得其所管理之资源”。
  26. 对原始资源的访问可能经由显示转换或隐式转换,一般而言显示转换比较安全,隐式转换比较方便。
  27. 如果在new表达式中使用[],必须在相应的delete表达式中也使用[]。如果在new表达式中不使用[],一定不要在相应的delete中使用[]。
  28. 以独立语句将newed对象存储于智能指针内。如果不这样做,一旦异常被抛出,有可能难以察觉的资源泄露。
  29. 好的接口容易被正确使用,而不是被误用。促进正确使用包括接口的一致性,以及内置类型的行为兼容。
  30. “阻止误用”的方法包括建立新类型,限制类型上的操作,束缚对象值,以及消除客户资源管理责任。
  31. tr1::shared_ptr支持定制型删除器,可以防范DLL问题,可以被用来自动解除互斥锁。
  32. CLASS的设计就是type的设计。
  33. 尽量以pass-by-reference-to-const替换pass-by-value。前者通常比较高效,并可避免切割问题。
  34. 以及STL的替代器和函数对象。对它们而言,pass-by-value往往比较适当。
  35. 成员函数的反面是非成员函数,而不是友元函数。如果需要为某个函数的所有参数进行类型转换,那么这个函数必须是非成员函数。
  36. 当std::swap对你的类型效率不高时,提供一个swap成员函数,并确定这个函数不抛出异常。
  37. 如果你提供一个member swap,也该提供一个non-member swap用来调用前者。对于classes也请特化std::swap。
  38. 调用swap时应针对std::swap使用using声明式,然后调用swap并且不带任何“命名空间资格修饰”。
  39. 为“用户定义类型”进行std templates全特化是好的,但千万不要尝试在std内加入某些对std而言全新的东西。
  40. 尽可能延迟变量定义式的出现时间。
  41. 尽量少做转型动作。特别是在注重效率的代码中避免dynamic_casts。如果有个设计需要转型动作,试着发展无需转型的替代设计。
  42. 如果转型是必要的,试着将他隐藏于某个函数的背后。客户随后可调用该函数,而不需要将转型放进他们自己的代码内。
  43. 宁可使用C++新样式转型,不要使用旧式转型。前者容易辨识,而且有着分门别类的优势。
  44. 避免返回handles(包括references、指针、迭代器)指向对象内部。遵循这个可以增加封装性,帮助const成员函数的行为像个const,并将“虚吊号码牌”的可能性降至最低。
  45. 带有异常安全函数的特征:1,不泄露任何资源。2,不允许数据被破坏。
  46. 异常安全函数即便发生异常也不会泄漏资源或允许任何数据结构的破坏。这样的函数区分可以分成:基本型、强烈型和不抛异常型。强烈保证往往能够以“copy-and-swap”实现出来,但“强烈保证”并非对所有函数都可实现或具备现实意义。
  47. 将大多数inlining限制在小型、被频繁调用的函数身上。可使日后的调试过程和二进制升级更容易,也可使潜在的代码膨胀问题最小化,是程序的速度提升机会最大化。
  48. 不要只因为function templates出现在头文件,就将他声明为inline。
  49. 如果使用object reference或object pointer可以完成任务,就不要使用objects。如果可以尽量以class声明式替换class定义式。为声明式和定义式提供不同的头文件。
  50. “public继承”意味着is-a。适用于base类身上的每一件事情也一定适用于derived classes身上,因为每一个derived class对象也是一个base class对象。is-a并非唯一存在于classes之间的关系。另两个常见的关系是has-a和is-implemented-in-terms-of。
  51. 应该避免遮掩继承而来的名称。
  52. public继承由接口继承和实现继承两种组成。在public下,派生类总是继承基类的接口。纯虚函数只具体指定接口继承。非纯虚函数具体制定接口继承以及缺省实现继承。非虚函数具体制定接口继承和强制实现继承。
  53. virtual函数的替代方案包括non-virtual interface手法以及strategy设计模式的多种形式。
  54. 绝不要重新定义继承而来的非虚函数。决不重新定义继承而来的缺省参数值。
  55. 可以通过复合模拟出has-a或根据某物实现出,其意义与public完全不同;在应用于,复合意味着有一个;在是咸鱼,副歌意味着根据某物实现出。
  56. private继承意味着根据某物实现出,与复合相比可以造成empty class最优化。
  57. 多重继承比单一继承复杂,可能导致新的歧义;但有正当用途。
  58. classes和templates都支持接口和多态。对类而言借口是显式的,以函数签名为中心。多态则是通过virtual函数发生于运行期;对templates而言,接口是隐士的,奠基于有效表达式。多态则是通过templates具现化和函数重载解析发生于编译器。
  59. typename具有双重意义。声明templates参数时,前缀关键字class和typename可以互换;使用typename标识嵌套从属类型,但不得在base class lists或member initalization list内以它做为base class修饰符。
  60. 模版生成多个类和多个函数,所以任何模板代码都不该与某个造成膨胀的模版参数产生相依存关系。因为非类型的模版参数而造成的代码膨胀,往往可以消除,做法是以函数参数或class成员变量替换templates参数;因类型参数造成的代码膨胀,往往可以降低,做法是让带有完全相同二进制表述的具现类型共享实现代码。
  61. 模版元编程可以将工作由运行期移往编译期,因为可以实现早期错误检测和更高的执行效率。
  62. set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用。
  63. opertaor new应该内含一个无穷循环,并在其中尝试分配内存,如果它无法满足内存需求,就应该调用new-handler。
  64. 当写一个placement operator new,请确定也写出了对应的plcaement delete。如果不这样做可能会发生隐蔽而时断时续的内存泄漏。
展开阅读全文

没有更多推荐了,返回首页