使用以下内容获得无法解释的行为:
a.cpp
编译为.dll库并在main.cpp
的main()中使用
Bar b;
//constr
Bar::Bar(){
//... initialize members
}
//private library init
Bar::init(){ ...}
//public API init
bool lib_init(){
b.init();
}
据我所知,由于全局变量的未定义初始化行为,这种方法可能会失败。
a.cpp
编译为.dll库并在main.cpp
的main()中使用
Bar* b;
//constr
Bar::Bar(){
//... initialize members
}
//private library init
Bar::init(){ ...}
//public API init
bool lib_init(){
b = new Bar;
b->init();
}
这次使用动态分配时可行。
a.cpp
编译为.dll库并在main.cpp
的main()中使用
static Bar& getBarObj()
{
static Bar g_objBar;
return g_objBar;
}
//constr
Bar::Bar(){
//... initialize members
}
//private library init
Bar::init(){ ...}
//public API init
bool lib_init(){
getBarObj().init();
}
与案例1相反,Bar obj实例化可能未定义,在案例3中,它是“根据请求”使用的。然而,案例3提供了与案例1相同的行为。
我的问题是......有谁能解释这里发生了什么? 所有内容都是使用VC2008 Release模式构建的(此项目的调试模式没有选项)
答案 0 :(得分:0)
在C ++中未定义来自不同文件的初始化的初始化顺序(你肯定有的情况)。这意味着如果依赖于在不同编译单元中的全局初始化期间构造的Bar b
,则程序未定义。
为什么Case 3应该起作用,是因为它迫使你使用一个函数来引用Bar b
,这个函数保证在这个函数返回的时候构造Bar b
。 / p>
如果您告诉我们您正在获得的确切未定义行为,并提供最少量的代码进行分析,我们可能会提供进一步的帮助。
P.S。您的Bar
构造函数是否依赖于另一个已构造的全局?
答案 1 :(得分:0)
案例1可能会失败,因为b
的构造基本上留给链接顺序(不受C ++规范控制:它是C ++的未定义行为,但行为可以由链接器定义! )
在任何情况下,一旦您致电lib_init
,b
被授予构建为lib_init
且b
留在同一模块中。
案例3在需要时构造b,并将在构造逆序中终止时与所有其他静态和全局对象一起销毁它。
如果Bar::Bar()
依次调用foo_init()
内置静态Foo
,则可能会对旧编译器造成一些问题:您需要Bar
和Bar
需要{{1但Foo
之前创建Bar
,Foo
之前Foo
在Bar
之前仍然需要它。
自2003年规格以来,这个事实应该再发生了。施工完成后需要进行破坏调度(Foo
ctor在Bar
ctor之前完成,因此在Foo
dtor之前终止将调用bar .dtor。
案例2是“丑陋的”:像案例3一样工作(根据需要创建)但有两个问题:
案例2可能更好地定义为
void lib_init()
{
static std::unique_ptr<Bar> p(new Bar);
p->init();
}
但这会使它像案例3一样。