您同时描述了不同的问题。在进行某种静态初始化的特定问题上,一种简单的方法是创建一个将执行注册的假类。然后每个不同的类都可以有一个static const X
成员,这个成员必须在翻译单元中定义,并且定义将触发实例的实例化和类的注册。
这并没有解决难题,即初始化订单惨败。该语言不对不同翻译单元中对象的初始化顺序提供任何保证。也就是说,如果你用这样的类编译三个翻译单元,就不能保证假成员的相对执行顺序。这也适用于库:如果您要在其中注册类的容器是全局/静态成员属性,则无法保证已初始化该容器。
如果您可以访问代码,您可以修改容器代码以使用static local variables
,这将是确保初始化顺序的一个步骤。作为可能解决方案的草图:
// registry lib
class registry { // basically a singleton
public:
static registry& instance() { // ensures initialization in the first call
static registry inst;
return inst;
}
// rest of the code
private:
registry(); // disable other code from constructing elements of this type
};
// register.h
struct register {
template <typename T>
register( std::string name ) {
registry::instance().register( name, T (*factory)() ); // or whatever you need to register
}
};
// a.h
class a {
public:
static a* factory();
private:
static const register r;
};
// a.cpp
const register a::r( "class a", a::factory );
// b.h/b.cpp similar to a.h/a.cpp
a
现在在这种情况下,和类的注册之间没有明确的顺序b
,但这可能不是问题。另一方面,通过在函数中使用局部静态变量registry::instance
,可以保证在对方法的任何调用之前registry::register
执行单例的初始化(作为对方法的第一次调用的一部分instance
)。
如果您无法进行该更改,那么您基本上不走运,并且您不能保证registry
将在其他翻译单元中的其他静态成员属性(或全局变量)之前实例化。如果是这种情况,那么您将不得不将类的注册推迟到第一次实例化,并向每个要注册的类的构造函数添加代码,以确保在实际构造对象之前注册类。
这可能是解决方案,也可能不是解决方案,具体取决于其他代码是否创建该类型的对象。在工厂函数的特定情况下(想到的第一个),如果不允许创建类型的对象a
或b
......那么在构造函数调用上捎带注册也不是解决方案。