条款1:尽量用const和inline而不用#define
以const 行使常量折叠,用inline 代替常用操作的宏定义,而且库里面有很多常用函数可用。当然不能抛弃宏,宏还是很有用滴。偶最近才发现宏的可爱之处。。。咔咔。
条款2:尽量用而不用
iostream的 IO智能,灵活,类型安全。呃,效率要比 stdio的IO低些。
条款3:尽量用new和delete而不用malloc和free
new/delete是转为C++设计的---它会自动调用构造析构函数。
恩,这也会造成不必要的性能损失。当new一个自定义类型的数组时,会调用类的默认构造函数,这时构造的对象往往不是所需要的---也就是所那些默认构造函数白调用了。这个问题可用C++的定位new表达式解决,然后需要时再在分配的内存上构造对象。删除时直接删除整块内存。不过偶在VC6下测试时发现析构函数没用调用,可能析构函数需要显式调用吧,这种情况岂不是跟用malloc/free时一样,那拿定位new表达式干嘛? orz---呃,除了这两种情况,任何情况下都不应显示调用析构函数,不然你会后悔的。
条款4:尽量使用c++风格的注释
一条无聊的条款,使用什么注释要看程序员的喜好与具体情况的。
条款5:对应的new和delete要采用相同的形式
就是new/delete,
new[]/delete[], malloc/free, calloc/free, ralloc/free必须配对。
条款6:析构函数里对指针成员调用delete
呃,在构造函数中分配资源,在析构函数中释放资源。这个与异常,new动态分配等合作得天衣无缝。
条款7:预先准备好内存不够的情况。
为了程序健壮点,进行错误检查是需要的。特别是new,万一抛出异常就不好玩了,虽然现在内存很便宜,很多人有海量内存。
条款8: 写operator
new和operator delete时要遵循常规。
条款9: 避免隐藏标准形式的new
条款10: 如果写了operator
new就要同时写operator
delete
自己做了什么事自己最清楚,解铃还需系铃人。
条款11: 为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符。
如果你知道不遵守这条规则使偶对着仅仅1000多行的代码调试了两天,你就知道不遵循这条条款的后果了。编译器很生气,后果很严重。
条款12: 尽量使用初始化而不要在构造函数里赋值。
对于自定义类型,在构造函数里复制会调用默认构造函数与拷贝构造函数,而那次默认构造函数的调用时不必的。所以初始话效率高的多,特别是大型复杂对象。但对于预定义类型则不需要,太多东东在初始化列表会搞的乱七八糟。
条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同。
因为类数据成员是按类声明中的顺序初始化的。遵循这条条款可以避免很多可怕的运行错误。
条款14: 确定基类有虚析构函数。
这是所有对象都能正常析构的保证。
条款15: 让operator=返回*this的引用。
所有重载运算符的行为都必须与预定义运算符的行为一致。为了能连续调用operator=(),必须让其返回*thist引用,不能是其它。
条款16: 在operator=中对所有数据成员赋值
对于有继承的情况,派生类的赋值运算符要调用基类的赋值运算符。保证基从类数据继承下来的数据成员正确复制。
条款17: 在operator=中检查给自己赋值的情况
有些operator=需要先释放自己占用的资源再进行赋值操作,此时这条款就成了必须了。免得搞得半死不活。
条款18: 争取使类的接口完整并且最小。
完整是显然的,没有完整接口的类拿来干嘛? 但完整的同时要保持的接口的最小化。类的接口太大难于掌握,而且容易引起歧义。最好是只提供一些原子操作。需要的话可提供一些常用复合操作以增加效率。
条款19: 分清成员函数,非成员函数和友元函数
条款20: 避免public接口出现数据成员
这是所有面向对象技术所BS的行为。不但丧失了类“封装”这一重要作用,而且容易出错。
条款21: 尽可能使用const
在所有能用const的地方都应加上const,包括数据定义声明,类函数成员声明。这样可避免一些可怕的运行错误而不会造成性能上的损失。多打几个字的代价肯定能赚回来。
条款22: 尽量用“传引用”而不用“传值”。
效率,效率,效率还是效率。呃,还要记住的是在能加const的地方都要加上, const引用
条款23: 必须返回一个对象时不要试图返回一个引用
这条条款是为效率狂准备的。任何时候返回一个临时对象的引用或地址都是可怕的行为。
条款24: 在函数重载和设定参数缺省值间慎重选择
条款25: 避免对指针和数字类型重载
条款26: 当心潜在的二义性。
条款27: 如果不想使用隐式生成的函数就要显式地禁止它。
如默认构在函数,拷贝构造函数,复制运算符,析构函数。。。。禁止很简单。声明为privated,并不提供定义。。。咔咔。。。当然有些时不能禁止的。如果不放心隐式生成的函数,那就自己提供一个。特别是有指针的时候。
条款28: 划分全局名字空间。
全局域只有一个。污染全局域的后果很严重。这里namespace正好派上用场了。
条款29: 避免返回内部数据的句柄。
条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低。
条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用
很明显返回局部变量的引用或地址得到的将是垃圾。 函数也不应该返回new来的对象的引用或地址。函数不一定是只有你用的,使用者不知道你的函数的实现方式,当然也不会轻易的动用delete咯,这也就造成了内存泄漏。 即使使用者这是你一个人,当函数的返回值散步与程序各处时,什么时候delete不是一个容易的判断。
条款32: 尽可能地推迟变量的定义
条款33: 明智地使用内联
内联可以避免函数调用的开销。短小常用的函数都应该内联。如果内联函数体非常短,编译器为这个函数体生成的代码就会真的比为函数调用生成的代码要小许多。这种情况,内联这个函数将会确实带来更小的目标代码和更高的缓存命中率!但在很多情况下,那内联都会增加代码体积。在一台内存有限的计算机里,过分地使用内联所产生的程序会因为有太大的体积而导致可用空间不够。即使可以使用虚拟内存,内联造成的代码膨胀也可能会导致不合理的页面调度行为(系统颠簸),这将使你的程序运行慢得象在爬。(当然,它也为磁盘控制器提供了一个极好的锻炼方式:))过多的内联还会降低指令高速缓存的命中率,从而使取指令的速度降低,因为从主存取指令当然比从缓存要慢。
还有就是
inline 只是程序员对编译器的建议,但决定权在编译器手上,当编译器认为你的函数不适合内联时。它就会以普通函数的形式处理你的函数,这样可能会带来函数重定义的错误。
构造函数和 析构函数不适于内联,因为这些函数的代码往往比你所看到的多。
最后一个就是有静态数据成员的函数和虚函数不能作为内联函数
条款34: 将文件间的编译依赖性降至最低
条款35: 使公有继承体现
"是一个"
的含义
条款36: 区分接口继承和实现继承
条款37: 决不要重新定义继承而来的非虚函数
条款38: 决不要重新定义继承而来的缺省参数值
条款39: 避免
"向下转换"
继承层次
条款40: 通过分层来体现
"有一个"
或 "用...来实现"
条款41: 区分继承和模板
条款42: 明智地使用私有继承
条款43: 明智地使用多继承
条款44: 说你想说的;理解你所说的
条款45: 弄清C++在幕后为你所写、所调用的函数
条款46: 宁可编译和链接时出错,也不要运行时出错
运行错误当然比编译连接错误麻烦多了。可是这条款是一句废话。错误是能选择的么?
条款47: 确保非局部静态对象在使用前被初始化
这句话好像应该说成:非静态局部变量和动态分配的对象使用前应初始化。非静态局部变量和动态分配的变量都是为初始化的,使用前当然应该初始化咯。全局变量和静态变量自动初始化为0。
条款48: 重视编译器警告
条款49: 熟悉标准库
标准库是个好东东。。。。咔咔
条款50: 提高对C++的认识
这不是废话么?呃。。。C++确实蛮复杂。 理解C++最好理解它的历史《The Design and
Evolution of C++》。呃。C++标准是最权威的手册。(两个偶都不喜欢看,D&E太无聊,标准太拗口。。。。 到时《The C++ programing language》《C++primer》《Inside The C++ Object Model》 和“深入C++系列”都很不错,呃。。。