每周技巧 #61:默认成员初始化器
本节阅读量:本文翻译自 Abseil 官网的 Tip of the Week #61: Default Member Initializers。
原文最初作为 TotW #61 发布于 2013 年 11 月 12 日。
更新于 2016 年 10 月。
声明默认成员初始化
默认成员初始化器会为成员在构造时声明一个默认值,看起来像这样:
|
|
这个默认初始化器会传播到该类的所有构造函数中,甚至包括 C++ 合成的构造函数。用这种方式初始化成员,对于拥有大量数据成员的类很有用,尤其是 bool、int、double 和原始指针这类类型。这些基本类型的非静态数据成员经常漏掉初始化,最终处于未初始化状态。不过,任何类型的非静态数据成员都可以有初始化器。
默认成员初始化器也适用于没有用户编写构造函数的简单 struct 声明:
|
|
成员初始化覆盖
如果类构造函数初始化了一个已经拥有默认初始化器的数据成员,那么构造函数中的初始化器会取代默认初始化器:
|
|
这段代码等价于旧式代码:
|
|
注意,前两个 Frobber 构造函数为它们的非静态变量提供了初始化器;这两个构造函数不会使用 length_ 的默认初始化器。而第三个 Frobber 构造函数没有为 length_ 提供初始化器,所以这个构造函数会使用 length_ 的默认初始化器。
和 C++ 中一贯的规则一样,所有非静态变量都按声明顺序初始化。
在 3 个 Frobber 构造函数中的前 2 个里,构造函数为 length_ 提供了初始化器。构造函数初始化器会取代默认成员初始化器,非静态类成员初始化器不会为这些构造函数贡献代码生成。
注意:较旧的文档可能把默认成员初始化器称为非静态数据成员初始化器,缩写为 NSDMI。
结论
默认成员初始化器不会让你的程序更快。它们会帮助减少遗漏带来的 bug,尤其是在有人添加新构造函数或新数据成员时。
小心不要把非静态类成员初始化器和静态类成员初始化器混淆:
|
|
这是一个较旧的特性。counter_ 是静态的,这是一条带初始化器的静态声明。它不同于非静态类成员初始化器,就像静态成员变量不同于非静态成员变量一样。