条款47: 确保非局部静态对象在使用前被初始化

news/2024/7/5 23:55:30
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

 

转载于:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/3934741.html


http://www.niftyadmin.cn/n/1079326.html

相关文章

python中assert函数,一个实用的技巧

Python中assert命令可用于判断该变量的值是否与预期的值一致 示范程序如下: a 4 assert a4 print("There is no mistake") # assert a3 print("Thats ok") 此时,在第二个assert函数使用的时候,先将其注释掉&#xff…

IGMP技术总结

转载自: IGMP技术总结 本博客(http://blog.csdn.net/livelylittlefish)贴出作者(三二一、小鱼)相关研究、学习内容所做的笔记,欢迎广大朋友指正! 1. IGMP 简介 IGMP 是Internet Group Manageme…

maven学习笔记二

安装配置略setting.xml文件使用默认示例程序1 新建hello-world文件夹2 在该文件夹中创建pom.xml文件1 <project xmlns"http://maven.apache.org/POM/4.0.0"2 xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"3 xsi:schemaLocat…

Displaytag的使用三

默认显示全部数据 1.加入jar包: commons-beanutils-1.7.0.jar commons-collections-3.2.jar commons-lang-2.2.jar commons-logging-1.1.jar displaytag-1.1.1.jar 2.加入资源文件 displaytag.properties 3.考入css&#xff0c;images&#xff0c;img三个文件夹 4.显示部分数…

将VIM打造成强大的IDE

转载自&#xff1a;所需即所获&#xff1a;像 IDE 一样使用 vim如侵犯您的版权&#xff0c;请联系&#xff1a;2378264731qq.com----------------------------------------------------------------------- 【正文】 开始前&#xff0c;我假设你&#xff1a;0&#xff09;具备基…

Displaytag的使用四

修改具体页面&#xff0c;实现如下&#xff1a; Java代码&#xff1a; <% List<Pojo2> list new ArrayList<Pojo2>(); Pojo2 p21 new Pojo2(); p21.setName("第一校区"); p21.setJieYue(10); p21.setGuiHua(8); p21…

创建新图像时,数据类型的设置,以及溢出问题

在介绍下面的bug时&#xff0c;我想让读者首先思考一个问题&#xff0c;在opencv中数字图中灰度值的数据类型是np.int还是np.uint8。在利用opencv进行图像处理时&#xff0c;用numpy.zeros创建了一个用于存储将要进行空域滤波处理的待处理图像&#xff0c;最开始以为将np.zeros…

Optimal Milking

poj2112:http://poj.org/problem?id2112 题意&#xff1a;K台挤奶机器&#xff0c;C头牛&#xff0c;K不超过30&#xff0c;C不超过200&#xff0c;每台挤奶机器最多可以为M台牛工作&#xff0c;给出这些牛和机器之间&#xff0c;牛和牛之间&#xff0c;机器与机器之间的距离&…