前言
C++标准中,处于同一编译单元(cpp)的全局对象按其声明次序初始化并倒序析构,但标准中没有定义处于不同编译单元的全局对象的初始化顺序。假如有个Log对象负责程序日志的记录,如果程序结束时,有某个全局对象出现类似于资源释放失败的错误,该对象会调用Log记录错误,这时,Log可能已经被销毁了,这就是所谓的dead-reference问题。
使用VC中的#pragma init_seg预处理指令可以解决这个问题。
#pragma init_seg(compiler)
#pragma init_seg(lib)
#pragma init_seg(user)
#pragma init_seg("user_defined_segment_name")
前三个指令,初始化优先次序依次降低,但都先于普通的全局变量构造,后于它们析构。
例如cout就是使用compiler级别构造的:
#pragma init_seg(compiler)
_CRTIMP2 ostream cout(&fout);
来自微软的详细描述:
http://support.microsoft.com/kb/104248
KB
Microsoft C++ 编译器可以通过使用 #pragama init_seg 预处理器指令在文件范围内控制您的静态对象的构造和析构。
有四个选项为 init_seg 预处理器指令:
#pragma init_seg(compiler) #pragma init_seg(lib) #pragma init_seg(user) #pragma init_seg("user_defined_segment_name")
此指令旨在使开发人员能够对构造函数分组,对于有依赖关系的对象这将很有用。使用 #pragma init_seg(compiler) 的对象在所有其他对象之前构造并在其它对象析构之后最后析构。这个指令一般用于运行时库中的对象。比如, cin 和 cout就在此分组里,如果你的对象也分在compiler组里面,在构造或析构里面使用cout时可能会遇到问题。
使用 #pragma init_seg(lib) 的对象构造于使用 #pragma init_seg(compiler)的对象之后,但是前于其它对象。使用 #pragma init_seg(user) 的对象构造于使用 #pragma init_seg(compiler) 和 #pragma init_seg(lib) 的对象之后。换句话说,本组与其它未分组的静态对象同时构造。
一种可以控制构造顺序的方法是更改链接顺序,同一init_seg分组里链接越早的模块构造越晚。
务必注意 C++ 语言不保证非派生对象的构造顺序 , C++ 语言保证基类早于派生类的对象构造。
#pragma init_seg("user_defined_segment_name") 预处理器指令将构造函数的地址放入到逻辑段"user_defined_segment_name"。 此选项仅仅在你需要修改启动代码的需求时,调用这些构造函数。
实例
下面的代码示例(四个源文件)演示上面的说法。 编译所有的源文件之后, 两种方式如下链接,运行它们。 从输出查看哪些init_seg 选项依赖链接顺序。使用 Visual C++ 32 位 Edition 版本:
link file1 file2 file3 file4 /out:demo1.exe link file4 file3 file2 file1 /out:demo2.exe
link file1 file2 file3 file4, demo1; link file4 file3 file2 file1, demo2
示例代码
// file1.cpp // command line: cl /c file1.cpp #pragma init_seg(compiler) #include<stdio.h> class MyCompClass { public: MyCompClass(){ printf("In the ctor of MyCompClass\n");} ~MyCompClass(){ printf("In the dtor of MyCompClass\n");} } MyComp;// file2.cpp // command line: cl /c file2.cpp #pragma init_seg(lib) #include<iostream.h> class MyLibClass { public: MyLibClass(){cout<<"In the ctor of MyLibClass"<<endl;} ~MyLibClass(){cout<<"In the dtor of MyLibClass"<<endl;} } MyLib;// file3.cpp // command line: cl /c file3.cpp #pragma init_seg(user) #include<iostream.h> class MyUserClass { public: MyUserClass(){cout<<"In the ctor of MyUserClass"<<endl;} ~MyUserClass(){cout<<"In the dtor of MyUserClass"<<endl;} } MyUser;// file4.cpp // command line: cl /c file4.cpp #include<iostream.h> class MyRegularClass { public: MyRegularClass(){cout<<"In the ctor of MyRegularClass"<<endl;} ~MyRegularClass(){cout<<"In the dtor of MyRegularClass"<<endl;} } MyRegular; void main(){}