Effective C++读书笔记

  1. 习惯C++
  2. 构造/析构/赋值运算
  3. 资源管理

随写随记

习惯C++

使用 #define的 缺点:

1. 宏被预处理器替换后,无法快速确定其意义
2. 对浮点常量, 使用常量会比宏导致较小量的码
3. #define无法为class创建专属常量. 一旦被定义,在其后编译过程中有效(除非某处被#undef)
4. 宏展开可能导致错误

enum的好处:

1. 避免让别人获得一个 pointer 或 reference 指向某个整数常量.
2. 避免非必要的内存分配(取决于编译器实现——是否为整数型 const 对象分配空间)
  1. 令声明const, 降低因错误而造成意外
  2. const成员函数: 确认该函数可作用于 const 对象身上.
  3. 两个成员函数如果只是常量性不同, 可以被重载.
  4. 编译器强制执行「成员函数只有在不改变对象之人和成员变量时才称为const」, 但程序中应使用“概念上的常量性”.
  5. 当 const 和 non-const 成员函数有着实质等价的实现时,令 non-const 调用 const版本可避免代码重复
  1. 初始化 != 赋值
  2. 成员初始化的时间在构造函数自动调用之时,比进入函数本体的时间早(初始化列表).
  3. 使用初始化列表初始化在某些情况下可以提高效率.
  4. 初始化列表可以避免成员变量是 const 或 reference 时不能赋值的问题.
  5. 将每个 non-local static 对象搬到一个属于自己的 static 函数里,返回一个 reference 指向它所包含的对象.可以避免「定义于不同编译单元内的 non-local static 对象初始化相对次序不确定问题」.

构造/析构/赋值运算

  1. 如果未声明 copy 构造函数, copy assignment 操作符(operator=),和析构函数, (当被调用时)那么编译器会自己声明上述函数.如果没有声明任何构造函数,编译器会声明一个 default 构造函数. 并且上述所有函数有是 public 且 inline. 除非该 class 的 base class自身

  2. operator= 只有生出的代码合法且有机会证明它有意义才会生成.

  1. 将 copy constructor 和 operator= 声明为private
  2. 继承 Uncopyable 类
1
2
3
4
5
6
7
8
9
10

class Uncopyable {
protect:
Uncopyable() {}
~Uncopyanle() {}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);

}
  1. 只为有 virtual 函数的 class 声明 virtual 析构函数 (因为虚函数表会增大对象体积)
  2. 适当的时候可以将 base class 的析构函数 设置为 pure-virtual 析构函数(当希望一个 class 作为抽象类)
  3. 给 base classes 一个virtual 析构函数只适用于 多态性质的 base classes 上.
  1. 析构函数不要吐出异常. 如果一个虚构函数调用的函数会吐出异常, 析构函数应该捕获任何异常, 并吞下(不传播)或者结束程序.

  2. 如果某个操作可能在失败时抛出异常,而又存在某种需要必须处理该异常, 那么这个异常必须来自析构函数以外的某个函数.

  1. 在构造函数和析构函数中, virtual 函数会失去多态性.原因是 virtual 函数指针直到子类对象被构建成功后才会指向子类虚函数表, 根据构造次序, 先构造 base class 部分, 再构造 derived class 部分, base class 构造函数调用的时候, 虚函数指针还指向 base class 的虚函数表,所以调用的是 base class 的函数.也就是在 base class 构造期间, 对象的类型是 base class 而不是 derived class, virtual 函数和运行期类型信息 都会把对象视为 base class 类型.

资源管理

script>