目录
使用这些函数之所以需要小心,其中一个原因是几乎一半的情况下编译器都会为我们生成代码。另一个原因是,C++ 默认时总是将类当作类似于值的类型,但是实际上并非所有的类型都类似于值(见第32条)。 知道何时应该显式地编写(或者禁止)这些特殊成员函数,并遵循本部分中的规则和准则来编写,将有助于确保代码的正确性、可扩展性和防错性。 本部分中我们选出的最有价值条款是第51条:析构函数、释放和交换绝对不能失败。 与编译器一致:成员变量初始化的顺序要与类定义中声明的顺序始终保持一致,不用考虑构造函数初始化列表中编写的顺序。要确保构造函数代码不会导致混淆地指定不同的顺序。 考虑以下代码: 这段代码隐藏着一个错误,危害性很大,而且很难发现。因为类定义中 email_是在 first_和last_之前被声明的,它将首先被初始化,然后试图使用其他未初始化的字段。更糟糕的是,如果构造函数的定义位于另一个文件夹,成员变量声明的顺序对构造函数的正确性的远距离影响就更难确定了。 C++ 语言之所以采取这样的设计,是因为要确保销毁成员的顺序是惟一的;否则,析构函数将以不同顺序销毁对象,具体顺序取决于构造对象的构造函数。为此带来的底层操作开销应该是不可接受的。 解决方案是,总是按成员声明的顺序编写成员初始化语句。这样,任何非法依赖都会显而易见。当然,尽量不让一个成员的初始化依赖于其他成员更好。 许多编译器(但不是所有)在我们违反了此条规则时会发出警告。
第47条 以同样的顺序定义和初始化成员变量
class Employee {
string email_, firstName_, lastName_;
public:
Employee( const char* firstName, const char* lastName )
: firstName_(firstName), lastName_(lastName), email_(firstName_ + "." + lastName_ + "@acme.com") {}
};