Effective C++ iterm4

条款四

--17/01/18

这个条款着重讲的是初始化问题。

(1)构造函数的初始化

最好使用member initialization list进行初始化,这里面存在着效率问题,因为如果在构造函数体内进行初始化的话,那么就会多调用一次default 构造函数,还有内置型对象需要手工初始化,所以一定要使用成员初值列。

(2)不同编译单元的初始化次序问题

不得不说我之前真的没考虑过类似问题,真的是打开了新世界大门啊!

这里主要存在问题的是不同编译单元的non-local static对象,这插播一下:

关于static的用法,C和C++中各有不同的用法,可以参考:

http://blog.csdn.net/majianfei1023/article/details/45290467

关于non-local static对象的说法,可以参考:

http://blog.csdn.net/zhangyifei216/article/details/50549703

里面代码用到了g++编译器进行编译,这里我看不懂,学习了一下:

http://blog.csdn.net/hnyzwtf/article/details/44674145

上面讲得很仔细了,什么是静态局部,什么是静态全局?这里的static对象指的是非堆区和栈区的变量,然后在函数内部定义的是local static对象,除此之外应该都是non-local static对象。不同编译单元指的就是有多个源代码文件,我们可以写个简单代码来验证类似问题(下面代码的编写和编译使用的是linux系统下的vim):

 1 //AB.h
 2 #ifndef AB_H
 3 #define AB_H
 4 #include <iostream>
 5 using namespace std;
 6 
 7 class A {
 8 public:
 9     A() : _val(10) { cout << "A is construct." << endl; }
10     int val() { return _val; }
11 private:
12     int _val;
13 };
14 
15 extern A a;
16 
17 class B {
18 public:
19     B() {
20         cout << "a value is " << a.val() << endl;
21         cout << "B is construct." << endl; 
22     }
23 };
24 #endif
25 
26 //A.cpp
27 #include "AB.h"
28 
29 A a;
30 
31 //B.cpp
32 #include "AB.h"
33 
34 B b;
35 
36 //main.cpp
37 #include <iostream>
38 using namespace std;
39 
40 int main() {
41     cout << "hello world!!" << endl;
42     return 0;
43 }

 

代码中A类似书中的文件系统,有且仅有一个,并且A的构造函数做的就是初始化是将自身的_val变量设为10,并且打印出“A is construct”,然后B要调用A的val()显示_val的值是什么,并且打印出“B is construc”。如果编译器足够聪明,它应该知道我们是要先编译A之后再编译B,不然的话A中的_val就没有被初始化。然而这个编译的顺序在编译器看来时可控,或者说他并没有帮我们设计好编译的顺序,我们打出下面的命令:

g++ A.o B.o main.o -o run1

按照A,B,main的顺序编译,自然输出我们想要的结果:

A is construct.
a value is 10
B is construct.
hello world!!

 

如果是按照B,A,main,也就是下面的命令:

g++ B.o A.o main.o -o run2

结果是:

a value is 0
B is construct.
A is construct.
hello world!!

_val没有被初始化。由此可以得出初始化相对次序并无明确定义。这是个不容忽视的大问题,因为你引用了没有初始化的值会导致一系列问题,因为使用没初始化的变量不是一件好事!

 

书上给出的解决方法是:将每个non-local static对象搬到自己的专属函数内,也就是另外写一个函数,里面放着该对象。这在设计模式里面称作singleton模式。下面给出需要改进的地方:

 1 //A.cpp
 2 #include "AB.h"
 3 
 4 A& a() {
 5     static A _a;
 6     return _a;
 7 }
 8 
 9 //AB.h
10 class B {
11 public:
12     B() {
13         cout << "a value is " << a().val() << endl;
14         cout << "B is construct." << endl; 
15     }
16 };

 

 

按照g++ B.o A.o main.o -o run2编译之后运行得到如下结果:

A is construct.
a value is 10
B is construct.
hello world!!

 

单例模式果然强大!!可行的原因如下:当你要用A对象的时候,你就调用a(),这时候如果_a没有初始化的话就初始化,已经初始化的话那么就直接返回_a,这就达到了我们全程只有一份A对象的目的了。

posted @ 2017-01-19 12:28  scoyer  阅读(193)  评论(0编辑  收藏  举报