NOVOTS KMS 词汇表 Glossary    联系我们 Contact Us
查询 Search  
   
按类别浏览 Browse by Category
NOVOTS KMS .: 数据库 .: 跨C++文件和库对静态对象进行初始化

跨C++文件和库对静态对象进行初始化

问题:
当你编译下面的C++程序的时候,你可能认为模块(module)中的对象会先编译并先初始化。
这种假设可能得不到预期的结果。

X.h :
#include <string>
using namespace std;    // 译者注: 加上这行
class CObjet {
  public:
     static const string STRINGX;
};

X.cpp:
#include <X.h>
using namespace std;    // 译者注: 这行可以不要
const string CObjet::STRINGX = "001";

Y.cpp:
#include <iostream>
#include <X.h>

const string STRINGY= CObjet::STRINGX;


int main () {
cout << "CObjet::STRINGX [" <<CObjet::STRINGX << "]" << endl;
cout << "STRINGY [" <<  STRINGY << "]" << endl;
return 0;
}


如果用下面的命令来编译:
xlC -c -I./ X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -o binary X.o Y.o

然后得到的结果如下:
./binary
CObjet::STRINGX [001]
STRINGY []    // 译者注: 该结果是AIX平台的, Linux平台可能会Segmentation fault
从这个结果来看,STRINGY并没有像预期的那样初始化为STRINGX
 
 
原因:
STRINGX和STRINGY是全局静态对象。STRINGY的初始化取决于STRINGX的初始化。两者定义在不同的源文件中。

虽然C++语言规范规定了同一个文件中这类对象的初始化顺序(按照定义的顺序),但并没有规定在跨文件或者库时这些对象的初始化顺序。

因此虽然模块X.o先编译, STRINGX仍可能会在STRINGY之后初始化, 这就形成了一个空的STRINGY.
取决于编译器和操作系统缓存中当前的值, STRINGY甚至可能包含了垃圾数据并导致程序运行时崩溃。
 
 
解决方案:
为了解决这个问题,一些开发者将每个非局部静态对象都移动到自己的函数中,并声明为静态的。并让这些函数返回这个静态对象的引用, 然后按照自己期望的对象初始化顺序来调用这些函数.虽然这通常是个可移植的方法,但是这需要修改代码。

XL C/C++编译器可以使得这项工作变得简单。你可以使用-qpriority或-qmkshrobj=priority(译者注: linux上只有-qmkshrobj形式) 或 -Wm,-c选项来指定定义在不同文件或者库中的静态对象的初始化顺序。这些选项会给每个模块赋予一个优先级值,然后根据该值来控制对象的初始化顺序。

包含主函数main()的模块通常优先级为0. 值越小表示优先级越高,在上面的例子中,可以在编译X.o的时候指定-qpriority=-100从而保证X.o中的对象在Y.o对象初始化之前初始化。

同样的,如果你想把X.o创建到一个共享库中,那么可以在创建该库的时候指定-qmkshrobj=-100。

即,你可以用下面的命令来编译:

xlC -c -I./ -qpriority=-100 X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -o binary X.o Y.o

或者, 创建共享库:
xlC -c -I./ X.cpp -o X.o
xlC -c -I./ Y.cpp -o Y.o
xlC -qmkshrobj=-100 -o libX.so X.o
xlC -o binary -btrl Y.o -L. -lX

这时执行程序就会得到如下结果:
./binary
CObjet::STRINGX [001]
STRINGY [001]

这篇文章对你多有用?

用户评语

添加评语
当前还没有评语.


.: .: .: .: .:
[ 登陆 ]
北京护航科技有限公司 2006

Novots Technologies Limited