在为拥有的翻译单元进行静态初始化之前,文件范围的静态对象是否已初始化为零?

时间:2013-10-29 12:45:34

标签: c++ static initialization standards

在文件maybe_use_foo.cpp中:

namespace {
    class Foo { /* ... */ };
    Foo* const the_foo = new Foo;
}

void funtion_callable_from_another_tu_during_process_wide_initialization() {
    // If we haven't yet run static initialization for this TU,
    // but some other static initializer called us, ignore the request.
    if (!the_foo)
      return;

    // OK, static initializers for this TU have run, foo exists, use it.
    the_foo->doSomething();
}

因此,无论上述情况是否可取,它是否始终有效?在我看来,它假定在TU运行的静态初始化之前静态是零初始化的。 C ++标准(C ++ 03?C ++ 11?)是否保证?

提出这个问题的另一种方法是询问当被解释为Foo *时,什么序列的值被保存在'the_foo'的存储器中。它绝对是{NULL / nullptr,new Foo},还是{undefined,new Foo},甚至是其他东西?

请不要建议其他组织方式:我不是在寻找有关如何做得更好的建议,我正在寻找对该技术合法性的更深入理解。

3 个答案:

答案 0 :(得分:4)

C ++ 11

[basic.start.init] / 2

  

具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量在进行任何其他初始化之前应进行零初始化(8.5)。

     

[...]

     

一起,零初始化和常量初始化称为静态初始化;所有其他初始化都是动态初始化。在进行任何动态初始化之前,应执行静态初始化。

也就是说,变量是零初始化的,但不是,它们在静态初始化之前不是零初始化(但是作为静态初始化的一部分)。


OP中的函数只会在动态初始化期间调用,因为它不会在零初始化期间调用,并且必须是constexpr函数才能成为常量初始化的一部分。

答案 1 :(得分:4)

是的,C ++ 03标准在[basic.start.init]中解释:

  

具有静态存储持续时间(3.7.1)的对象应在进行任何其他初始化之前进行零初始化(8.5)。

8.5.1解释:

  

零初始化T类型的对象意味着:

     

- 如果T是标量类型(3.9),则将对象设置为0(零)转换为T的值;

     

[..]

答案 2 :(得分:0)

您的代码可能会导致错误。链接器通常不会尝试深入理解单独模块中的初始化部分。尝试通过静态函数提供变量,例如

namespace {
    Foo* the_foo() {
        static Foo* g_ = new Foo;
        return g_;
    }
}