为了解决由静态(反)初始化命令失败引起的问题,我尝试使用Nifty Counter 成语 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
条形图.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
酒吧.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
标准数据文件
#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"