条款47: 确保非局部静态对象在使用前被初始化
class FileSystem { ... }; // 这个类在你 // 的程序库中 FileSystem theFileSystem; // 程序库用户 // 和这个对象交互 ////////////////////////////////////////////////////////// class Directory { // 由程序库的用户创建 public: Directory(); ... }; Directory::Directory() { 通过调用theFileSystem的成员函数 创建一个Directory对象; }
Directory tempDir; // 临时文件目录
现在,初始化顺序的问题变得很明显了:除非theFileSystem在tempDir之前被初始化,否则,tempDir的构造函数将会去使用还没被初始化的theFileSystem。但theFileSystem和tempDir是由不同的人在不同的时间、不同的文件中创建的。怎么可以确认theFileSystem在tempDir之前被创建呢?
在某个特定的编译单元(即,源文件)中,构造函数可以确保对象在创建时被初始化;但如果在某个编译单元中,一个对象的初始化要依赖于另一个编译单元中的另一个对象的值,并且这第二个对象本身也需要初始化,事情就会变得更复杂。
非局部静态对象指的是这样的对象:
· 定义在全局或名字空间范围内
· 在一个类中被声明为static,或
· 在一个文件范围被定义为static。局部静态对象:函数内的static对象
对于不同被编译单元中的非局部静态对象,你一定不希望自己的程序行为依赖于它们的初始化顺序,因为你无法控制这种顺序。即:你绝对无法控制不同编译单元中非局部静态对象的初始化顺序。
解决方案:首先,把每个非局部静态对象转移到函数中,声明它为static。其次,让函数返回这个对象的引用。这样,用户将通过函数调用来指明对象。换句话说,用函数内部的static对象取代了非局部静态对象
虽然关于 "非局部" 静态对象什么时候被初始化,C++几乎没有做过说明;但对于函数中的静态对象(即,"局部" 静态对象)什么时候被初始化,C++却明确指出:它们在函数调用过程中初次碰到对象的定义时被初始化。所以,如果你不对非局部静态对象直接访问,而用返回局部静态对象引用的函数调用来代替,就能保证从函数得到的引用指向的是被初始化了的对象。这样做的另一个好处是,如果这个模拟非局部静态对象的函数从没有被调用,也就永远不会带来对象构造和销毁的开销;而对于非局部静态对象来说就没有这样的好事。
class FileSystem { ... }; // 同前 FileSystem& theFileSystem() // 这个函数代替了 { // theFileSystem对象 static FileSystem tfs; // 定义和初始化 // 局部静态对象 // (tfs = "the file system") return tfs; // 返回它的引用 } class Directory { ... }; // 同前 Directory::Directory() { 同前,除了theFileSystem被 theFileSystem()代替; } Directory& tempDir() // 这个函数代替了 { // tempDir对象 static Directory td; // 定义和初始化 // 局部静态对象 return td; // 返回它的引用 }
以上方法常用于单例模式的实现
有两个全局对象,我们知道,放在同一个CPP中时会按序初始化(编译器按序生成构造函数调用),如果这两个全局对象在不同的CPP中,有没有方法能控制其构造函数调用次序呢?(链接问题)
全局对象的初始化次序在C++标准中没有定义。
可以这样做:
假设你需要一个类A的对象a,这么写(使用局部静态对象,返回它的引用)
A& getA()
{
static A a;
return a;
};
这样能够保证使用a的时候a已经被初始化了。
参考:
http://bbs.csdn.net/topics/30293003