今天早上我和一位同事讨论了静态变量初始化顺序。他提到了Nifty/Schwarz 柜台,我(有点)困惑。我了解它是如何工作的,但我不确定这在技术上是否符合标准。
假设以下 3 个文件(前两个是从More C++ Idioms复制粘贴的):
//Stream.hpp
class StreamInitializer;
class Stream {
friend class StreamInitializer;
public:
Stream () {
// Constructor must be called before use.
}
};
static class StreamInitializer {
public:
StreamInitializer ();
~StreamInitializer ();
} initializer; //Note object here in the header.
//Stream.cpp
static int nifty_counter = 0;
// The counter is initialized at load-time i.e.,
// before any of the static objects are initialized.
StreamInitializer::StreamInitializer ()
{
if (0 == nifty_counter++)
{
// Initialize Stream object's static members.
}
}
StreamInitializer::~StreamInitializer ()
{
if (0 == --nifty_counter)
{
// Clean-up.
}
}
// Program.cpp
#include "Stream.hpp" // initializer increments "nifty_counter" from 0 to 1.
// Rest of code...
int main ( int, char ** ) { ... }
...这就是问题所在!有两个静态变量:
- “漂亮的计数器”在
Stream.cpp
;和 - 中的“初始化程序”
Program.cpp
。
由于这两个变量恰好位于两个不同的编译单元中,因此没有(AFAIK)官方保证在调用构造函数nifty_counter
之前初始化为 0 。initializer
我可以将两个快速解决方案视为“有效”的两个原因:
- 现代编译器足够聪明,可以解决两个变量之间的依赖关系,并将代码以适当的顺序放置在可执行文件中(极不可能);
nifty_counter
实际上就像文章所说的那样在“加载时”初始化,并且它的值已经放在可执行文件的“数据段”中,所以它总是在“任何代码运行之前”被初始化(很有可能)。
在我看来,这两者都依赖于一些非官方但可能的实现。这个标准是否符合标准,或者这只是“很可能起作用”以至于我们不应该担心它?