与技术一相比,这种技术更简单,也更清晰
技术基于事实,函数内部的静态对象在函数第一次被调用时初始化,且只被
初始化一次
真正想解决的不是静态对象什么时候被初始化,而是确保正确的初始化顺序
技巧很灵巧 对于如何初始化依赖因素来说,可以把一个静态对象放在一个能
返回对象引用的函数中
两个互相依赖的类
第一个类包含一个bool类型的成员,它只由构造函数初始化,所以能够知道该
类的一个静态实例是否调用了工作方式
//: C10:Dependency1.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#ifndef DEPENDENCY1_H
#define DEPENDENCY1_H
#include <iostream>
class Dependency1 {
bool init;
public:
Dependency1() : init(true) {
std::cout << "Dependency1 construction"
<< std::endl;
}
void print() const {
std::cout << "Dependency1 init: "
<< init << std::endl;
}
};
#endif // DEPENDENCY1_H ///:~
构造函数也显示它是什么时候被调用的,为了知道对象是否被初始化,可以
通过print()函数打印出对象的状态
第二个类初始化由第一个类的一个对象来完成,这会导致初始化相互依赖
//: C10:Dependency2.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#ifndef DEPENDENCY2_H
#define DEPENDENCY2_H
#include "Dependency1.h"
class Dependency2 {
Dependency1 d1;
public:
Dependency2(const Dependency1& dep1): d1(dep1){
std::cout << "Dependency2 construction ";
print();
}
void print() const { d1.print(); }
};
#endif // DEPENDENCY2_H ///:~
构造函数显示它自己并打印出对象dl的状态,所以能够知道当构造函数被
调用时,dl是否已经初始化了
为了说明会出现什么错误,下面的文件首先以一种不正确的顺序定义静态
对象,如果在对象Dependency之前连接器碰巧初始化对象Dependency2,错误
就会出现
为了有更多的可读性的输出,增加separator()函数内部的静态对象在函数第一次被调用时初始化,且只被
诀窍就是不能全局地调用一个函数,除非该函数用来执行一个变量的初始化
操作,所以separator()函数返回一个哑元值用来初始化两个全局变量
//: C10:Technique2.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include "Dependency2.h"
using namespace std;
// Returns a value so it can be called as
// a global initializer:
int separator() {
cout << "---------------------" << endl;
return 1;
}
// Simulate the dependency problem:
extern Dependency1 dep1;
Dependency2 dep2(dep1);
Dependency1 dep1;
int x1 = separator();
// But if it happens in this order it works OK:
Dependency1 dep1b;
Dependency2 dep2b(dep1b);
int x2 = separator();
// Wrapping static objects in functions succeeds
Dependency1& d1() {
static Dependency1 dep1;
return dep1;
}
Dependency2& d2() {
static Dependency2 dep2(d1());
return dep2;
}
int main() {
Dependency2& dep2 = d2();
getchar();
} ///:~
函数d1()和d2()包含类Dependency1和Dependency2的静态对象
输出
Initializer()
performing initialization
Initializer()
Dependency2 construction Dependency1 init: 0
Dependency1 construction
---------------------
Dependency1 construction
Dependency2 construction Dependency1 init: 1
---------------------
Dependency1 construction
Dependency2 construction Dependency1 init: 1
使用技术二。
通常,静态对象在单独的文件中定义,而不是在单独的文件中定义一个包含
静态对象的函数。但是需要在头文件中声明
//: C10:Dependency1StatFun.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#ifndef DEPENDENCY1STATFUN_H
#define DEPENDENCY1STATFUN_H
#include "Dependency1.h"
extern Dependency1& d1();
#endif // DEPENDENCY1STATFUN_H ///:~
实际上,关键字 extern 对于函数声明来说是多余的
//: C10:Dependency2StatFun.h
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#ifndef DEPENDENCY2STATFUN_H
#define DEPENDENCY2STATFUN_H
#include "Dependency2.h"
extern Dependency2& d2();
#endif // DEPENDENCY2STATFUN_H ///:~
在前面的顺序文件中,有静态对象定义,现在,改为在包装的函数定义中
定义静态对象
//: C10:Dependency1StatFun.cpp {O}
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include "Dependency1StatFun.h"
Dependency1& d1() {
static Dependency1 dep1;
return dep1;
} ///:~
其他的代码也可以放在这些头文件中,下面是另外一个文件
//: C10:Dependency2StatFun.cpp {O}
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
#include "Dependency1StatFun.h"
#include "Dependency2StatFun.h"
Dependency2& d2() {
static Dependency2 dep2(d1());
return dep2;
} ///:~
现在有两个文件,这两个文件可以以任意的顺序连接
如果它们只包含普通的静态对象,那么可以产生任意顺序的初始化
在这里因为它们包含定义静态对象的函数,所以不会出现不正确的初始化
//: C10:Technique2b.cpp
// From Thinking in C++, 2nd Edition
// Available at http://www.BruceEckel.com
// (c) Bruce Eckel 2000
// Copyright notice in Copyright.txt
//{L} Dependency1StatFun Dependency2StatFun
#include "Dependency2StatFun.h"
int main() { d2(); getchar();} ///:~
当运行这个程序时,将会发现Dependency1类的静态对象的初始化总是发生在
类Dependency2的静态对象的初始化之前
我们也许想在函数d1()和d2()的头文件中把它们声明为内联函数,但是我们
必须明确地知道这样做不行
输出
Initializer()
performing initialization
Initializer()
Dependency1 construction
Dependency2 construction Dependency1 init: 1