在文件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},甚至是其他东西?
请不要建议其他组织方式:我不是在寻找有关如何做得更好的建议,我正在寻找对该技术合法性的更深入理解。
答案 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_;
}
}