初始化之前使用的静态映射

Static map used before it is initialized

本文关键字:静态 映射 初始化      更新时间:2023-10-16

我正在尝试实现这样的工厂模式。

现在的问题是程序在寄存器函数中以段错误终止,因为映射尚未初始化。

// initialise the registered names map
std::map<std::string, factoryMethod> SourceFactory::registeredClasses_ = { };
bool SourceFactory::Register(std::string name, factoryMethod createMethod) {
// registeredClasses_ = { }; // This prevents the segfault but does not work for obvious reasons
auto temp = std::make_pair(name.c_str(), createMethod);
std::pair<std::map<std::string, factoryMethod>::iterator, bool> registeredPair =
SourceFactory::registeredClasses_.insert(temp);
return registeredPair.second;
}

为什么可以在映射初始化之前调用Register()?我尝试初始化头文件中的映射,但随后出现链接器错误

源工厂的多重定义::registeredClasses_

解决方案是设置静态布尔isInitialized=false,然后相应地初始化映射。但我希望这可以避免。

在初始化注册表之前从不同的转换单元调用Register是可能的。
不幸的是,添加静态标志不会解决任何问题,因为它也不会被初始化。

一个方便的解决方案是添加间接级别:

// static
std::map<std::string, factoryMethod>& SourceFactory::registry()
{
static std::map<std::string, factoryMethod> registeredClasses;
return registeredClasses;
}
bool SourceFactory::Register(const std::string& name, factoryMethod createMethod) {
auto temp = std::make_pair(name, createMethod);
return registry().insert(temp).second;
}

这是一个常见的问题,称为静态初始化顺序惨败

在命名空间范围内具有静态存储持续时间的对象是在翻译单元中按顺序构造的,但您不知道其他翻译单元中的对象是否可以先进行初始化。

不要将容器放在命名空间范围内,而是将其设置为静态函数(可能从新的GetRegistry()函数返回?(,以便在首次使用时构造它。这可能是从main使用,从另一个静态持续时间"事物"的初始化中使用(这可能是你的Register调用来自的地方(,从月球使用......

这也是为什么编写单例的正确方法是拥有一个GetInstance()函数,该函数声明(staticly!(函数范围内的实例。

一个解决方案是设置一个静态布尔值isInitialized=false,然后相应地初始化映射。但我希望这可以避免。

不。这样,您不仅会对isInitialized标志产生相同的问题,而且您无法对该信息"执行任何操作"。除了在初始值设定项中,您不能"初始化"其他内容,整个问题是尚未使用初始值设定项。你可以分配给地图,但这会有未定义的行为,因为你会分配给尚不存在的东西......然后它无论如何都会被初始化!