规则一 永远在使用对象之前将它初始化

  1. int x = 0;
  2. const char* text = "A C-style string";
  3. double d;
  4. std:: cin >> d;
  5. // 对于内置类型的初始化必须手工完成,其他类型的初始化职责落在构造函数身上。

规则二 确保每一个构造函数都将对象的每一个成员初始化

这个规则很简单,重要的是不要混淆赋值和初始化操作。

  1. class PhoneNumber { ... };
  2. class ABEntry {
  3. public:
  4. ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones);
  5. private:
  6. std::string theName;
  7. std::string theAddress;
  8. std::list<PhoneNumber> thePhones;
  9. int numTimesConsulted;
  10. }
  11. ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones) {
  12. theName = name;
  13. theAddress = address; // 这些都是赋值
  14. thePhones = phones; // 而非初始化
  15. numTimesConsulted = 0;
  16. }

C++规定,对象的成员变量的初始化动作发生在进入构造函数本体之前。

初始化发生时间更早,发生于这些成员的default构造函数被自动调用之时(比进入ABEntry构造函数本体的时间更早)。numTimeConsulted例外,因为是内置类型。

规则三 member initialization list(成员初值列)替换赋值操作

  1. ABEntry::ABEntry(const std::string& name, const std::string& address, const std::list<PhoneNumber>& phones)
  2. : theName(name),
  3. theAddress(address), // 现在,这些都是初始化(initialization)
  4. thePhones(phones),
  5. numTimeConsulted(0)
  6. { } // 现在,构造函数本体不必做任何动作

这个构造函数和上一个的最终结果都相同,但通常效率较高。因为赋值那个版本首先调用default构造函数为theName, theAddress和thePhones设初值,然后立刻再对它们赋予新值。default构造函数的一切动作因此浪费了。第二版避免了这个问题,因为初值列中针对各个成员变量而设的参数,被拿出作为各成员变量之构造函数的实参。theName以Name为初值进行copy构造,对于内置类型,其初始化和赋值的成本相同,但是为了一致最好也通过成员初值列来初始化。 同样道理,甚至当你想要default构造一个成员变量,你都可以使用成员初始值,只要指定无物作为初始化实参即可。

  1. ABEntry::ABEntry()
  2. :theName(), // 调用theName的default构造函数
  3. theAddress(),
  4. thePhones(),
  5. numTimesConsulted(0) // 记得将numTimesConsulted显式初始化为0
  6. {}

规则四 C++有着十分固定的"成员初始化次序"

base classes更早于其derived classes被初始化,而class的成员变量总是以其声明次序被初始化,即使在成员初值列中以不同的次序出现,夜不会有任何影响。

规则五 “不同编译单元内定义之non-local static对象”的初始化次序

所谓static对象,其寿命从被构造出来直到程序结束为止,因此stack和heap-based对象都被排除。

函数内的static对象称为local static对象(因为它们对函数而言是local),其他static对象称为non-local static对象。

程序结束时static对象会被自动销毁,也就是它们的析构函数会在main()结束时被自动调用。

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

C++对“定义于不同编译单元内的non-local static对象”的初始化次序并无明确定义。如果一个引用了另外一个未初始化的话,就会出错。

  1. class FileSystem {
  2. public:
  3. ...
  4. std::size_t numDisks() const;
  5. ...
  6. };
  7. // 调用
  8. extern FileSystem tfs;
  9. class Directory {
  10. public:
  11. Directory( params );
  12. ...
  13. };
  14. Directory::Directory( params ) {
  15. ...
  16. std::size_t disks = tfs.numDisks(); // 使用tfs对象
  17. }
  18. Directory tempDir( params );

除非tfs在tempDir之前先被初始化,否则tempDir的构造函数会用到尚未初始化的tfs。然而,C++对“定义于不同的编译单元内的non-local static对象”的初始化相对次序并无明确定义。

规则六 non-local static 对象被local static对象替换

  1. class FileSystem { ... };
  2. FileSystem& tfs() {
  3. static FileSystem fs;
  4. return fs;
  5. }
  6. class Directory { ... };
  7. Directory::Directory( params ) {
  8. ...
  9. std::size_t disks = tfs().numDisks();
  10. ...
  11. }
  12. Directory& tempDir() {
  13. static Directory td;
  14. return td;
  15. }

以上设计,如果再把它们的构造函数设置为private的话,就是一种Singleton设计模型

总结

  1. 对内置类型对象进行手工初始化,因为C++不保证初始化它们。
  2. 构造函数最好使用成员初值列,而不要再构造函数本体内使用赋值操作。初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同。
  3. 为免除“跨编译单元之间初始化次序“问题,请以local static 对象替换non-local static对象。

Effective C++ 条款04:确定对象被使用前已经先被初始化的更多相关文章

  1. Effective C++ -----条款04:确定对象被使用前已被初始化

    为内置型对象进行手工初始化,因为C++不保证初始化它们. 构造函数最好使用成员初值列,而不要在构造函数本体内使用赋值操作.初值列列出的成员变量,其排列次序应该和它们在class中的声明次序相同. 为免 ...

  2. EC读书笔记系列之2:条款4 确定对象被使用前已先被初始化

    条款4:确定对象被使用前已先被初始化 记住: ★为内置对象进行手工初始化,因为C++不保证初始他们 ★构造函数最好使用初始化列表,而不要在构造函数本体内使用赋值操作.初始化列表列出的成员变量,其排列次 ...

  3. [effictive c++] 条款04 确定对象被使用前已被初始化

    成员初始化 在c和c++ 中,使用为初始化的类型经常会引发不可预料的错误,从而使得我们要花费巨大的时间用于调试查找问题,所以确定对象被使用前已被初始化是个非常好的习惯. 永远在使用之前对对象进行初始化 ...

  4. Effective C++ 条款四 确定对象被使用前已被初始化

    1.对于某些array不保证其内容被初始化,而vector(来自STL)却有此保证. 2.永远在使用对象前初始化.对于无任何成员的内置类型,必须手工完成.      int x = 0;      c ...

  5. [Effective C++ --009]确定对象被使用前已先被初始化

    在确保对象在使用前已先被初始化这一条款的编码实践中,作者为我们总结了三条经验,它们分别是: ------------------------------------------------------ ...

  6. Effective C++ 之 Item 4:确定对象被使用前已先被初始化

    Effective C++ Chapter 1. 让自己习惯C++ (Accustoming Yourself to C++) Item 4. 确定对象被使用前已先被初始化 (Make sure th ...

  7. 读书笔记 effective c++ Item 4 确保对象被使用前进行初始化

    C++在对象的初始化上是变化无常的,例如看下面的例子: int x; 在一些上下文中,x保证会被初始化成0,在其他一些情况下却不能够保证.看下面的例子: class Point { int x,y; ...

  8. Effective C++学习笔记 条款04:确定对象被使用前已先被初始化

    一.为内置类型对象进行手工初始化,因为C++不保证初始化它们. 二.对象初始化数据成员是在进入构造函数用户编写代码前完成,要想对数据成员指定初始化值,那就必须使用初始化列表. class A { pu ...

  9. Effective C++ -----条款12: 复制对象时勿忘其每一个成分

    Copying函数应该确保复制“对象内的所有成员变量”及“所有base class成分”. 不要尝试以某个copying函数实现另一个copying函数.应该将共同机能放进第三个函数中,并由两个cop ...

随机推荐

  1. 认识tornado(一)

    tornado 源码包中 demos 目录下包含一些示例程序,就从最简单的 helloworld.py 来看一个 tornado 应用程序的代码结构. 完整的实例程序如下: 01 #!/usr/bin ...

  2. 编写高质量代码--改善python程序的建议(三)

    原文发表在我的博客主页,转载请注明出处! 建议十三:警惕eval()的安全漏洞 相信经常处理文本数据的同学对eval()一定是欲罢不能,他的使用非常简单: eval("1+1==2" ...

  3. Codevs (3657括号序列 )

    题目链接:传送门 题目大意:中文题,略 题目思路:区间DP 这个题是问需要添加多少个括号使之成为合法括号序列,那么我们可以先求有多少合法的括号匹配,然后用字符串长度减去匹配的括号数就行 状态转移方程主 ...

  4. 【BZOJ1509】[NOI2003]逃学的小孩 直径

    [BZOJ1509][NOI2003]逃学的小孩 Description Input 第一行是两个整数N(3  N  200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的 ...

  5. Mac下安装apk(命令形式)

    1 连接上设备 2 卸载原有程序 3 进入adb程序目录/Applications/adt-bundle-mac-x86_64-20131030/sdk/platform-tools 4 键入命令 . ...

  6. jpa双向一对多关联映射

    表结构 Room类 package auth.model; import java.util.HashSet; import java.util.Set; import javax.persisten ...

  7. 巨蟒python全栈开发-第11天 第一类对象 闭包 迭代器

    一.今日主要内容总览(重点) 1.第一类对象->函数名=>变量名 (1)函数对象可以像变量一样进行赋值 (2)还可以作为列表的元素进行使用 (3)还可以作为返回值返回 (4)还可以作为参数 ...

  8. ubuntu-16.04.2-server-amd64.iso

    w

  9. gunicorn

    https://blog.csdn.net/jailman/article/details/78496522 gunicorn工作原理 Gunicorn“绿色独角兽”是一个被广泛使用的高性能的Pyth ...

  10. 深入理解Mysql索与事务隔离级别

    1. 概述 1.1 定义 锁是计算机协调多个进程或线程并发访问某一资源的机制. 在数据库中,除了传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供需要用户共享的资源.如何保证数据并 ...