要解决由static (de-)initialization order fiasco引起的问题,我尝试使用Nifty Counter idiom aka Schwartz Counter。但是,我注意到,如果包含静态初始值设定项的头文件包含在Visual Studio的预编译头中,则它不起作用。在这种情况下,我在调试器中看到,静态初始化程序的构造函数在之后被称为另一个静态对象的构造函数。
如果我在#include "stdafx.h"
之后立即声明了一个额外的静态初始值设定项,或者编辑了预编译的标题以使其不包含声明,则它会按预期工作。
任何可能导致这种情况的想法?
修改
我终于能够在一个新的虚拟项目中重现这个问题:
Foo.cpp中
#include "stdafx.h"
#include "Foo.h"
#include <cassert>
#include <iostream>
#ifdef NIFTY
static int SchwartzCounter; // zero initialized at load time
static typename std::aligned_storage<sizeof(Foo), alignof (Foo)>::type foo_buf;
Foo& foo = reinterpret_cast<Foo&>(foo_buf);
#else
Foo foo;
#endif
Foo::Foo()
{
std::cout << __func__ << std::endl;
}
Foo::~Foo()
{
std::cout << __func__ << std::endl;
}
void Foo::doSomething()
{
std::cout << __func__ << std::endl;
assert(x == 42);
}
#ifdef NIFTY
FooInitializer::FooInitializer()
{
std::cout << __func__ << std::endl;
if (SchwartzCounter++ == 0)
{
new (&foo) Foo();
}
}
FooInitializer::~FooInitializer()
{
std::cout << __func__ << std::endl;
if (--SchwartzCounter == 0)
{
(&foo)->~Foo();
}
}
#endif
foo.h中
#pragma once
class Foo
{
public:
Foo();
~Foo();
void doSomething();
private:
int x = 42;
};
#ifdef NIFTY
extern Foo& foo;
static struct FooInitializer {
FooInitializer();
~FooInitializer();
} fooInitializer;
#else
extern Foo foo;
#endif
Bar.cpp
#include "stdafx.h"
#include "Foo.h"
#include "Bar.h"
#include <cassert>
#include <iostream>
#ifdef NIFTY
static int SchwartzCounter; // zero initialized at load time
static typename std::aligned_storage<sizeof(Bar), alignof (Bar)>::type bar_buf;
Bar& bar = reinterpret_cast<Bar&>(bar_buf);
#else
Bar bar;
#endif
Bar::Bar()
{
std::cout << __func__ << std::endl;
foo.doSomething();
}
Bar::~Bar()
{
std::cout << __func__ << std::endl;
}
void Bar::doSomething()
{
std::cout << __func__ << std::endl;
assert(x == 42);
}
#ifdef NIFTY
BarInitializer::BarInitializer()
{
std::cout << __func__ << std::endl;
if (SchwartzCounter++ == 0)
{
new (&bar) Bar();
}
}
BarInitializer::~BarInitializer()
{
std::cout << __func__ << std::endl;
if (--SchwartzCounter == 0)
{
(&bar)->~Bar();
}
}
#endif
Bar.h
#pragma once
class Bar
{
public:
Bar();
~Bar();
void doSomething();
private:
int x = 42;
};
#ifdef NIFTY
extern Bar& bar;
static struct BarInitializer {
BarInitializer();
~BarInitializer();
} barInitializer;
#else
extern Bar bar;
#endif
stdafx.h中
#pragma once
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
// If the following define is commented out, the nifty counter idiom is not used
#define NIFTY
// If the following include is commented out while the nifty counter idiom is used, the initialization order is correct
#include "Foo.h"