非静态全局对象与指向动态对象的全局指针



出现以下无法解释的行为:

案例1:

a.cpp编译为.dll库,并在 main(( 中使用main.cpp

Bar b; 
//constr
Bar::Bar(){
  //... initialize members
}
//private library init
Bar::init(){ ...}
//public API init
bool lib_init(){
  b.init();
}

据我了解,这种方法可能会由于全局变量的未定义初始化行为而失败。

案例2:

a.cpp编译为.dll库,并在 main(( 中使用main.cpp

Bar* b; 
//constr
Bar::Bar(){
  //... initialize members
}
//private library init
Bar::init(){ ...}
//public API init
bool lib_init(){
  b = new Bar;
  b->init();
}

这一次,当使用动态分配时,它起作用了。

案例3(最令人惊讶(

a.cpp编译为.dll库,并用于 main(( 的 main.cpp

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 相反,在情况 1 中,Bar obj 实例化可能未定义,而在情况 3 中,它是"根据请求"使用的。然而,案例 3 提供与案例 1 相同的行为。

我的问题是...谁能解释一下这里发生了什么?一切都是使用 VC2008 发布模式构建的(此项目没有调试模式选项(

来自不同文件的全局变量的初始化顺序(您肯定有这种情况(在 C++ 中未定义。这意味着,如果您依赖于在不同编译单元中的全局初始化期间构造Bar b,则您的程序是未定义的。

为什么情况 3 应该有效,是因为它强制您使用函数来引用Bar b并且此函数保证在此函数返回时Bar b已经构造。

如果您告诉我们您得到的确切未定义行为,并提供最少数量的代码进行分析,我们也许能够进一步提供帮助。

附言您的Bar构造函数是否依赖于已构造的另一个全局?

情况 1 可能会失败,因为 b 的构造基本上留给链接顺序(不受C++规范控制:它是C++的未定义行为,但行为可以由链接器定义!无论如何,一旦你调用lib_init b就被授予被构造lib_initb离开在同一个模块中。

案例 3 在需要时构造 b,并将在终止时以与所有其他静态和全局对象相反的构造顺序销毁它。如果Bar::Bar()依次调用内部具有静态Foofoo_init(),这可能会给旧编译器带来一些问题:您需要BarBar需要FooBar是在Foo之前创建的,Foo Bar该垫子仍然需要它之前销毁。自 2003 年规范要求销毁计划在施工完成后进行(因此Foo ctor 在 ctor 之前完成Bar因此 bar dtor 将在 Foo dtor 之前终止时调用。

案例 2 是"丑陋的":像案例 3(按需创建(一样处理 cotruction,但有两个问题:

  • 指针应该是静态的,只是为了避免在多次调用 lib_init(( 和 ...
  • 谁会摧毁巴尔?操作系统将在终止时将内存重新压缩,但不会调用 dtor。

案例 2 可能应该更好地定义为

void lib_init()
{
    static std::unique_ptr<Bar> p(new Bar);
    p->init();
}

但这会使它像案例 3。

相关内容

  • 没有找到相关文章

最新更新