条款4:确定对象被使用前已先被初始化

记住:

  ★为内置对象进行手工初始化,因为C++不保证初始他们

  ★构造函数最好使用初始化列表,而不要在构造函数本体内使用赋值操作。初始化列表列出的成员变量,其排列次序应和它们在class中的声明次序相同

  ★为免除“跨编译单元之初始化次序”问题,请以local static对象替换non-local static对象

-----------------------------------------------------------------------------------------------------------------------------------------------------------

1 区别赋值初始化

举例:

 class ABEntry {

     public:
ABEntry( const std::string &name, const std::string &address,
const std::list<PhoneNumber>& phones
);
private:
std::string theName;
std::string theAddress;
std::list<PhoneNumber> thePhones;
int numTimesConsulted;
}; ABEntry::ABEntry( const std::string &name, const std::string &address,
const std::list<PhoneNumber>& phones
) { theName = name; //这些都是赋值而非初始化
theAddress = address;
thePhones = phones;
numTimesConsulted = ;
}

  而C++规定对象的成员变量的初始化发生在进入构造函数本体之前。改进如下:

 ABEntry::ABEntry( const std::string &name, const std::string &address,
const std::list<PhoneNumber>& phones
)
:theName(name), //现在这些都是初始化
theAddress(address),
thePhones(phones),
numTimesConsulted()
{ } //构造函数本体无需任何动作

这样效率高的原因:

  第一个版本首先需调用default构造函数为theName等设初值,然后再立刻对它们赋新值。default构造函数的一切作为因此浪费了。而版本二初始化列表中的各个实参被拿去作为各成员变量之构造函数的实参。

  内置型对象其初始化和赋值成本一样,但为了一致性最好也通过初始化列表来初始化。

当欲要default构造一个成员变量,甚至都可以使用初始化列表,只要指定无物即可,如下:

 ABEntry::ABEntry( const std::string &name, const std::string &address,
const std::list<PhoneNumber>& phones
)
:theName( ), //现在这些都空,会调用theName的default构造函数,下同
theAddress( ),
thePhones( ),
numTimesConsulted() //记得将内置类型显式初始化为0
{ } //构造函数本体无需任何动作

有时可以合理地在初始化列表中遗漏那些“赋值表现像初始化一样好”的成员,改用它们的赋值操作,并将那些赋值操作移往某个函数(通常是private),供所有构造函数(若有多个构造函数的话)调用。此做法在“成员变量的初值系有文件或数据库读入”时特别有用。

C++成员初始次序很固定:base classes早于derived classes;成员变量以声明次序被初始化。

2 不同编译单元内定义之non-local static对象的初始化次序问题

一点一点来解释:

① 所谓static对象包括(3类):

  global对象;

  定义于namespace作用域内的对象;

  在classes内,函数内,以及在file作用域内被声明为static的对象

注:函数内的static对象成为local static对象,其他static对象称为non-local static对象

② 所谓编译单元:

  产出单一目标文件的那些源码。基本上它是单一源码文件加上其所含入的头文件。

举例:

 class FileSystem {  //来自你的程序库
public:
...
std::size_t numDisks() const; //众多成员函数之一
...
};
extern FileSystem tfs; //预备给客户使用的对象

若用户建立了一个class用来处理文件系统内的目录,很自然其class会用上FileSystem对象:

 class Directory {  //由程序库客户建立
public:
Directory( params );
...
}; Directory::Directory( params ) {
...
std::size_t disks = tfs.numDisks(); //使用tfs对象
...
}

进一步假设,这些客户决定创建一个Directory类型的对象:

Directory tempDir( params );

现在初始化次序的重要性显现出来了:除非tfs先于tempDir被初始化。而C++对“定义于不同编译单元内的non-local static对象”的初始化相对次序并无明确定义!!!

如下设计可消除上面问题:

  将每个non-local static对象搬到自己的专属函数内(该对象在此函数内被声明为static)。这些函数返回一个reference指向它所含的对象。然后用户调用这些函数,而不直接指涉这些对象。这个技巧基础在于:c++保证,函数内的local static对象会在:“该函数被调用期间”“首次遇上该对象之定义式”时被初始化。所以若你以“函数调用”(返回一个reference指向local static对象)替换“直接访问non-local static对象”,你就获得了保证!!!

改进后程序如下:

 class FileSystem {...};     //同前
FileSystem& tfs() { //用此函数来替换tfs对象。该函数在
//FileSystem类中可能是个static。这类函数称为 //reference-returning函数,适合写成inline函数,下同 static FileSystem fs; //local static对象!!!
return fs;
} class Directory {...}; //同前
Directory::Directory( params ) { ...
std::size_t disks = tfs().numDisks(); //函数来替换对象!!!
...
} Directory& tempDir() { //此函数用来替换tempDir对象。该函数在
//Directory类中可能是个static static Directory td;
return td;
}

最新文章

  1. 使用Object.create 克隆对象以及实现单继承
  2. webpack初学
  3. 查看最点CPU的语句
  4. Asp.Net中文本换行
  5. Windows 8.1 归档 —— Step 1 选择与安装
  6. 第k大数问题
  7. fedora 20下安装vim的C++补全插件clang_complete
  8. Leetcode_191_Number of 1 Bits
  9. 应不应该使用inline-block代替float
  10. 数据结构-堆(应用篇)之堆排序法-C和C++的实现
  11. R语言︱词典型情感分析文本操作技巧汇总(打标签、词典与数据匹配等)
  12. 关于jQuery中的trigger和triggerHandler方法的使用
  13. LG3834 可持久化线段树1
  14. Python入门:Anaconda和Pycharm的安装和配置
  15. 【MOOC EXP】Linux内核分析实验七报告
  16. Tensorflow 之finetune微调模型方法&amp;&amp;不同层上设置不同的学习率
  17. [No0000C2]WPF 数据绑定的调试
  18. [smarty] 在smarty模板中使用smarty变量初始化 javascript 变量的问题
  19. nuxt 脚手架创建nuxt项目中不支持es6语法的解决方案
  20. Excel2013复制内容粘贴到刷选的数据表中

热门文章

  1. Android使用Google推荐的联网框架Volley,让连接网络更加简单
  2. BZOJ 1833 ZJOI2010 count 数字计数 数位DP
  3. 乐酷工作室孙志伟:Testin云測试有广度有深度 省钱省力值得信赖
  4. UVa 1583 Digit Generator(数学)
  5. 从头开始-06.C语言中预处理指令
  6. asp.net mvc ajax提交例子
  7. EXT属性
  8. 网页设计之PS画渐变线条
  9. Python : 熟悉又陌生的字符编码(转自Python 开发者)
  10. pycharm的激活