条款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

 

posted @ 2014-08-25 13:32  合唱团abc  阅读(308)  评论(0编辑  收藏  举报