条款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对象取代了非局部静态对象

虽然关于 "非局部" 静态对象什么时候被初始化,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

时间: 2024-10-29 22:12:38

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

读书笔记 effective c++ Item4 确保对象被使用前进行初始化

Item4 确保对象被使用前进行初始化 C++在对象的初始化上是变化无常的,例如看下面的例子: Int x; 在一些上下文中,x保证会被初始化成0,在其他一些情况下却不能够保证.看下面的例子: Class Point { Int x,y; }; Point p; P的数据成员有时候保证能够被初始化(成0),有时候却不能.如果你从不存在未初始化对象的语言中转到c++, 就需要注意了,因为这很重要. 使用未初始化对象的坏处 读取未初始化的值会产生未定义的行为.在一些平台中,仅仅读取未初始化的值就会让

局部静态变量是如何做到只初始化一次的?

关于编译选项 -Wa,-adlhn参考 http://blog.csdn.net/lanxinju/article/details/5900986 以下内容来自于内网别的高人的回复 可以写个程序测试一下: class A { public: A() {} public: int a; }; int static_var_func() { static A a; return a.a++; } int main(int argc, char * argv[]) { static_var_func(

四种不同对象的生存方式(栈、堆、全局、局部静态)

[结果分析,引申出四种对象]: 生存方式 执行时机 消亡时机 全局(静态)对象 全局静态存储区global 比程序进入点更早,构造函数先被执行: 程序结束前,其析构函数被执行. 局部静态对象 局部静态存储区local static 在对象诞生时,其构造函数被执行.(注意,此处只会有一个实例产生,而且固定在内存上(非stack也非heap),它的构造函数在控制权第一次移转到其声明处时被调用. 程序将结束时(此对象因而将遭致毁灭)其析构函数才被执行,但比全局对象的析构函数更早一步执行. 局部对象 栈

静态对象与非静态对象

Java静态对象和非静态对象有什么区别?? 静态对象                                                        非静态对象      是类共同拥有的.                                          是类独立拥有的, 内存空间上是固定的                                              空间在各个附属类里面分配 先分配静态对象的空间                   

C++ 静态对象

一:什么是静态对象? 对象的存储方式是静态的. 局部静态对象和类的静态对象. 局部静态对象:一个变量在函数内部定义,其生命周期跨越了该函数的多次调用.局部对象确保不迟于在程序执行流第一次经过该对象的定义语句时进行初始化.这样的对象一旦被创建,在程序结束之前都不会销毁.在定义局部静态对象的函数执行完毕后,该静态对象不会撤销.当该函数被多次调用的过程中,静态局部对象会持续存在并保存它的值. 静态成员对象:静态成员对象存储在全局存储区,静态成员对象的作用域在类的作用域中.其可以避免与其他类成员或全局对

effective c++学习笔记条款4-7

条款4:确定对象被使用前已经初始化 一. 变量在不同情况下可能会初始化,也可能不会初始化. 注意初始化和赋值的区别. 1.在类中内置类型不会发生隐式初始化,自定义有默认构造函数的能被默认初始化 所以在构造类时务必初始化内置类型,最好给自定义的对象显示初始化避免在函数体中赋值浪费资源. 2.内置类型在函数体内不会初始化,在函数体外自动初始化为0. 二. 1.const和引用类型必须初始化,不可能赋值 三 1.当类实在是有较多构造函数,并且总是要对一些成员数据重复初始化,可以考虑将那些“赋值和初始化

Exceptional C++: [Item 47. Control Flow] [条款47 控制流]

条款47控制流 难度:6 你到底有多了解C++代码的执行顺序呢?通过这个问题来测试一下你的知识. "恶魔藏在细节里."尽量指出下面(人为)代码的问题,请集中在控制流相关的问题上. #include <cassert> #include <iostream> #include <typeinfo> #include <string> using namespace std; // The following lines come from

条款4:确定对象被使用前已被初始化(Make sure that objects are initialized before they&#39;re used)

其实 无论学何种语言 ,还是觉得要养成先声明后使用,先初始化再使用. 1.永远在使用对象之前先将其初始化. 内置类型: 必须手工完成. 内置类型以外的:使用构造函数完成.确保每一个构造函数都将对象的一个成员初始化. shit!!读到这,以前一直以为有些概念独自觉悟到的,大牛们也有这样的想法!!!! 2.区分开assignment & initialization(这个需要再看看,似乎以前的认知是错误的!!!!) initializatin:在default构造函数时才是对非内置类型做初始化. a

局部静态变量

1 #pragma region 成员函数的局部静态变量应用 2 class CTestA 3 { 4 public: 5 CTestA(); 6 void ReturnCurrentTime(float currentFrame, float nextFrame); 7 }; 8 9 CTestA::CTestA(){} 10 11 void CTestA::ReturnCurrentTime(float currentFrame, float nextFrame) 12 { 13 stati