Effective c++ 札记1

1.空类?
当我们没有手动声明新的构造函数时,编译器会声明以下几个:
默认构造 拷贝构造 =号运算符 析构
惟有当这些函数被需要(被调用) ,它们才会被编译器创建出来。(这个以前还真不知道)

2.阻止上面的暗处的声明的方法
方法一:将其设为private(这样外部就无法访问),并且不写其定义(这样内部或友元也无法访问)
方法二:继承一个Uncopyable类

3.析构函数中的异常

c++类中的析构函数允许抛出异常,但这样做是极不受推荐的

如果有两个同类型的异常同时存在(这种情况在当类成员包含容器时会经常出现),那么程序若不是结束执行就很可能会导致不明确的行为
原则:
任何时候,析构函数都不要抛出异常,也尽量不要把可以抛出异常的语句写在析构函数中,而是应该把这些语句作为一个close函数成员。即使迫不得已要在析构中写可能抛出异常的语句,也要把它catch掉

4.为什么要少用#define

4.1

比如说#diefine aa 1.112321  就不如用const double aa = 1.112321

在编译的目标码中,就可能会有多个1.112321
而使用const就会得到较小量的码量,因为aa会进入符号表
4.2
可控其作用域
如可用
class test
{ ..
static const int NumTurn = 5
..
}来把NumTurn作为一个类的const静态成员。但静态变量是很特殊的,在class test声明里的只是一个声明(别看它不是函数哦!)。我们如果不用去取这个NumTurn的地址的话,只用声明就可以用了。但是要取地址的话,我们必须在全局作用域写上:
const int test::NumTurn = 5; 或直接写const int test::NumTurn(因为声明时已有初值)
4.3
作为一个类成员,取代define 的作用还可以使用 enum {NumTurn = 5};  注:取enum的地址不合法
4.4
define出的函数很容易出错,典型的就是传入一个带++的参数的时候可能会++多次。这时候用inline函数就好了

5.有关初始化列表

为什么用初始化列表而不是在构造函数里初始化
构造函数里做的东西其实不能叫什么初始化,它只是赋值。因为在构造函数的赋值前,已经有一个我们看不见的初始化过程。这个初始化过程会调用成员变量自身的默认构造函数(如果不是内建类型的话,如int),然后我们又在构造函数里用了一次拷贝构造,造成了效率的低下。初始化列表则可以解决这个问题。
5.1
如果成员是const ,就一定要用初始化列表。总是使用成员初值列。这样做有时候绝对必要,且又往往比赋值更高效。
5.2顺序问题之一
初始化的顺序是以声明时的顺序为准的,而不管你的初始化列表是什么顺序。
5.3顺序问题之二
c++中属于多个目标文件中的全局变量的构造顺序是无法确定的,若它们有依赖关系,则……
解决方法:用单件模式去取代全局的变量(把这个全局变量作为一个全局函数的static成员,这个全局函数去取出这个static成员)
5.4多线程时的问题
non-conststatic对象,不论它是local 或non-local,在多线程环境下”等待某事发生”都会有麻烦(这个还没能完全理解,先放这儿吧,看看以后有没有更深的体会)

 

 

One Response

发表评论

电子邮件地址不会被公开。 必填项已用*标注