摘要
- #define:宏的名称是不会进入符号表中(symbol table),宏在符号表中只是其对应的数值/表达式。
- 对于形似函数的宏,最好改用inline函数替换之。
- 成员初始化列表是在执行构造函数体前运行的代码,因此它们是真正的对成员数据进行初始化,从而避免了默认的构造函数调用以及拷贝构造等操作 。
- 为避免“跨编译单元之初始化次序”问题,请以局部静态对象替换非局部静态对象。(编译单元:是指产出单一目标文件的源码,通常是一个源文件加上一个头文件的组合)
- 如果class没有定义构造函数、析构函数、拷贝构造函数、拷贝赋值运算符函数,那么C++内部会动创建一个默认的构造函数、析构函数、拷贝构造函数、拷贝赋值运算符函数。并且这些默认函数都是public且inline的。
- 如果一个基类将拷贝赋值运算符声明为private,那么编译器就拒绝为派生类生成默认的拷贝赋值运算符。因为派生类如果想使用这些函数,那么这些函数会相应的处理基类成份,但是基类是private的,所以不可以使用。
- STL容器如vector、list、set,trl::unordered_map等等,这些容器都不带有虚析构函数,所以如果当你定义一个类继承于这些容器,然后再使用容器基类指针释放你自己定义的类对象,那么将会产生错误。
- C++并不禁止析构函数抛出异常,但是不建议这样,析构函数绝对不要抛出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕获并处理该异常
- 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class(比起当前执行构造函数和析构函数的那层)。
- “以对象管理资源”的思想(RAII):获得资源后立刻放进管理对象内:获得资源之后将其封装到类中,例如shared_ptr等智能指针。实际上“以对象管理资源”的观念常被称为“资源获得时机便是初始化时机”(Resource Acquisition Is Initialization,RAII)
管理对象运用析构函数确保资源被释放:当离开作用域之后,对象可以调用析构函数自动的释放资源,而无须我们手动释放。但是如果析构函数抛出异常,可能需要自己手动处理
赋值RAII对象必须一并复制它所管理的资源,所以资源的拷贝行为决定RAII对象的拷贝行为。 - 普遍而常见的RAII类拷贝行为是:抑制拷贝、试行引用计数法。不过其他行为也都可能被实现。
- APIs往往要求访问原始资源,所以每一个RAII类应该提供一个“取得其所管理的资源”的办法。
- 绝不要返回指针/引用指向一个局部stack对象,或返回一个引用指向heap-allocated对象,或者返回一个引用/指针指向一个静态局部变量。
- 变量定义需要执行构造与析构函数,因此在某些情况下为了提高程序的效率,应该延迟变量定义的时间。
- 即使拥有虚内存,inline造成的代码膨胀也会造成额外的换页行为,降低指令高速缓存装置的集中率,以及伴随效率的损失。
- 隐式内联:当成员函数定义在类的内部时,这个函数是隐式inline的(隐式内联只有这一种情况)
- 如果你令class D以public形式继承class B,你便是告诉编译器:每一个类型为D的对象同时也是一个类型为B的对象。反之不是;B对象可使用的地方,D对象一样可以使用。反之不是
- 为了让被隐藏的名称(重写)再见天日,可使用using声明式或转交函数
- 纯虚函数的一些特征:
拥有纯虚函数的类不能实例化
拥有纯虚函数的类,其派生类必须实现该纯虚函数 - 绝对不要重新定义一个继承而来的缺省参数值,因为缺省参数值都是静态绑定,而virutal函数——你唯一应该覆盖的东西——却是动态绑定。
- private继承意为“is-implemented-in-terms-of(根据某物实现出)”。它通常比复合(composition)的级别低。但是当derived class需要访问protected base class的成员,或需要重新定义继承而来的virtual函数时,这么设计时合理的。
- set_new_handler允许客户指定一个函数,在内存分配无法获得满足时被调用。
- 当你写一个placement operator new时,请确定也写出了对象的placement operator delete。如果没有这样,你的程序可能会发生隐微而时断时续的内存泄漏
Reference
[1] [c++ primer plus]
[2] [Effective C++]