假设我想实现一种查找表作为
std::map<std::string, int>
,例如:
// Utils.hpp header
class Utils
{
public:
static std::map<std::string, int> NameToId;
static int GetIdForName(const std::string & name)
{
auto it = NameToId.find(name);
if (it != NameToId.end())
return it->second;
else
return -1; // not found
}
};
对应的.cpp文件中:
// Utils.cpp
#include “Utils.hpp”
std::map<std::string, int> Utils::NameToId = {
{“foo”, 10},
{“bar”, 20},
…
};
有这样一个
static std::map
成员变量安全吗?
这是否会因
std::map
(和 std::string
)动态初始化而导致细微的错误?
这是我在 redis 客户端中修复的一个错误:
客户端类可以创建订阅者对象(您需要一个客户端对象来创建订阅者):
class Client {
public:
Subscriber subscriber() { ... }
};
订阅者包含这样一个(无序但相同的)静态映射:
class Subscriber {
public:
static std::map<...> table;
}
现在,当您将两件事结合起来时,乐趣就开始了:
Client
类的方法使用 Subscriber::table
进行一些查找(因为我们不喜欢 switch
和 if else
)。好吧,实际上它使用了 Subscriber
的静态方法,并且使用了静态成员,但无论如何......按照初始化-销毁的顺序,你拥有的是
就在步骤 3 和 4 之间,客户端可能有一些未处理的消息队列,当它开始处理它们时,它将必须使用死对象的静态属性。在所有那些死去的物体中。客户端和静态成员都位于全局空间中,我们只是碰巧在另一个静态成员之前初始化了客户端。
将其与客户端可能有多个并行操作的订阅者的事实混合在一起(公平地说,有一个线程正在运行,直到处理完内容 - 因此客户端对象必须在析构函数完成之前处理剩余数据),并且您有一个这是让你对消毒剂报告失去理智的好方法。享受