转:不同编译单元内定义的non-local static 对象的初始化顺序

《Effective C++》条款4中提到了”留意不同编译单元内的non-static变量的初始化顺序“

下文的描述得很详细,转载过来了。

http://blog.csdn.net/chgaowei/article/details/6001433

static对象包括global对象,定义于namespace作用域的对象,在class内的对象,在函数内,以及file作用域内被声明为static的对象。

local-static 对象指的是定义在函数内部的对象。其他的被称为non-local-static对象。

编译单元是指产生单一目标文件的代码,通常是一个源程序和它所include的头文件。

问题

有两个类的定义:

class Test1

{

public :

Test1()

{

printf("Test1 构造函数./n");

          t2.test();

}

virtual

~Test1( )

{

printf("Test1 析构函数./n");

}

void test()

{

printf("Test1 test 函数/n");

}

};

class Test2

{

public :

Test2()

{

printf("Test2 构造函数./n");

}

virtual

~Test2( )

{

printf("Test2 析构函数./n");

}

void test()

{

printf("Test2 test 函数/n");

}

};

int main()

{

printf("Hello World!/n");

return 1;

}

两个源文件:Test1.c,Test2.c分别有两个定义:

Test1 t1;

Test2 t2;

测试环境为linux AS5.0,GCC。Makefile文件中编译顺序为:Test2.c, Test1.c

t1和t2是non-local static变量,他们的构造是在main函数之前进行的。

编译并执行,打印为:

Test1 构造函数.

Test2 test 函数

Test2 构造函数.

Hello World!

Test2 析构函数.

Test1 test 函数

从上面的打印可以看出:

1、  t1和t2是non-local static变量,他们的构造是在main函数之前进行的。

2、  t1和t2的构造顺序和Makefile中编译时文件名的顺序相反。

3、  析构函数在main函数退出时进行。且析构顺序和构造顺序正好相反。

4、  由于t1构造函数中调用了non-local static变量t2,而t2此时还没有进行构造。可能会造成严重的后果。

为了避免在对象构造前访问,可以更改Makefile中编译单元的编译顺序来解决。

除此之外,还有一个更好的方法:

将每个non-local static对象搬到自己的专属函数内,这些函数返回一个指向对象的reference,而不再直接访问对象。

Test1 *GetT1()

{

static Test1 t1;

return &t1;

}

Test2 *GetT2()

{

static Test2 t2;

return &t2;

}

同时,Test1的构造函数更改为:

Test1()

{

printf("Test1 构造函数./n");

          GetT2->test();

}

这样,无论Makefile中编译单元的前后顺序如何,t1构造时访问t2时,可以确保t2已经被构造:

Test1 构造函数.

Test2 构造函数.

Test2 test 函数

Hello World!

Test2 析构函数.

Test1 test 函数

另外,这种方法还可以减少全局变量的个数,使对变量的使用可以监控。

注:t1和t2也可以定义为static,不过这样在引用t2的时候需要费点周折。

时间: 2024-10-31 12:39:19

转:不同编译单元内定义的non-local static 对象的初始化顺序的相关文章

C++编译单元和命名空间

编译单元 编译单元,指的是代码的物理组织形式.根据C++标准,每一个cpp 文件就是一个编译单元. 编译器不会去编译 `.h` 或者 `.hpp` 文件: 编译器只会编译 `.c` 或 `.cpp` 文件: 简单来说,当一个c或cpp文件在编译时,预处理器首先递归包含头文件,这也就是为什么常会有:#ifndef--#define--#endif.之后,形成一个含有所有必要信息的单个源文件,这个源文件就是一个编译单元.这个编译单元会被编译成为一个与cpp文件名同名的目标文件 . 编译器不能检查跨越

在成员函数内定义static变量

成员函数内的局部变量可以是static的.如果将成员函数内的某个局部变量定义为静态变量,该类的所有对象在调用这个成员函数时将共享这个变量. 例3-40   本例在成员函数m中定义了一个static变量s,由于s定义在程序块内,它拥有程序块范围,因此它只能在m内部访问.每调用m一次,s就会相应地增加一次.又因为m是C的成员函数,所以,C的所有对象都共享这个静态局部变量.这样,对m的每一次调用访问的都是同一个s.相反,对于非静态局部变量x来说,每个C对象都拥有一个x.所以,在main中第一次调用c1

(转)MVC语法[email protected]和@functions(Razor内定义函数)

(转)MVC语法[email protected]和@functions(Razor内定义函数) 转自:http://www.mikesdotnetting.com/Article/173/[email protected]@Functions-In-WebMatrix The Difference Between @Helpers and @Functions In WebMatrix This is another post which was inspired by a recent qu

此编译单元不包含在frame元数据中指定的factoryClass,无法加载配置的运行时共享库

警告:此编译单元不包含在frame元数据中指定的factoryClass,无法加载配置的运行时共享库.要在没有运行时共享库的情况下进行编译,请将 -static-link-runtime-shared-libraries  选项设置为true, 或删除 -runtime-shared-libraries 选项. 通过修改FlashBuilder4\Adobe Flash Builder 4\sdks\4.0.0\frameworks  下的flex-config.xml,将 <static-li

C++类内定义静态变量

C++类内定义静态变量只限定与integral类型,比如int.char.long.float.double都行,但是string不行 #include<iostream> #include<string> using namespace std; class testClass { public: static const int _dataI = 2; static const long _dataL = 389l; static const char _dataC = 'A'

JS function的定义方法,及function对象的理解。

废话篇: 今天看到了javascript的原型链,各种指向,各种对象有木有,各种晕,各种混淆有木有.兼职是挑战个人脑经急转弯的极限啊.不过,最终这一难题还是被我攻克了,哇咔咔.现在就把这东西记下来,免得到时候又忘了就悲催了.... 正文篇: function的定义方法,及function对象的理解. 在我大js中秉承着一切都是对象的原则,不论是方法还是其他都不例外. 我们在使用java的时候经常要编写方法,这时候其用的关键字是function,而在js中我们在编写函数的时候也是用这个关键字,所以

c++总结之类型,对象的定义和声明,对象的初始化和赋值

一.对象的类型 对象的类型决定了对象占用内存空间的大小,和内存的布局,内存中可存储值的范围以及对该对象可以进行的操作,由于对象的类型决定可以对其执行的操作,因此const属性也可以看做对象类型的组成部分.类型又分为静态类型和动态类型,对于普通对象,静态类型和动态类型一般是一致的:对于指针和引用类型,静态类型和动态类型可以相同也可以不同,静态类型是指针和引用定义时声明的类型,而动态类型是指程序运行时实际绑定的类型.当静态类型和动态类型不同时,一般来说有两种情况:一是指涉到常量的指针和引用绑定了一个

java 编译时的初始化顺序

有的时候,java的初始化会对我的工作照成很大影响,所以简单介绍一下, 首先介绍简单的变量的初始化:在类的内部,变量定义的先后顺序决定了初始化的顺序,即使变量定义散布于方法定义之间,它也会先于构造器和方法初始化. public class Test{    public static void main(String[] args){        Test2 test2 = new Test2();        test2.f();    }}class Test1{    public T

[转] 关于VS中区分debug与release,32位与64位编译的宏定义

在vs编程中,常常涉及到32位和64位程序的编译,怎么判断当前编译是32位编译还是64位编译?如何判断 是debug下编译还是release下编译?因为之前用到,这里记录一下,省的忘了又要疯狂的google. 1.判断是debug编译还是release编译. 如果_DEBUG定义了表示是debug编译,否则是release编译. 2.判断是32位编译还是64位编译. 在 Win32 配置下,_WIN32 有定义,_WIN64 没有定义.在 x64 配置下,两者都有定义.即在 VC 下,_WIN3