C++ 强制静态成员初始化

C++ 强制静态成员初始化,c++,initialization,static-members,C++,Initialization,Static Members,我有一个类,它包含一个静态成员,一个字符串到函数指针的映射。此映射打算使用一组静态映射填充一次,并且随后不会被修改 我的问题是,如何确保地图在初始化之前不被访问?我的代码当前看起来像这样: class MyClass { static MapType s_myMap; public: static const MapType& getTheMap() { if (s_myMap.empty()) { // Populate the map

我有一个类,它包含一个静态成员,一个字符串到函数指针的映射。此映射打算使用一组静态映射填充一次,并且随后不会被修改

我的问题是,如何确保地图在初始化之前不被访问?我的代码当前看起来像这样:

class MyClass
{
  static MapType s_myMap;
public:
  static const MapType& getTheMap()
  {
    if (s_myMap.empty())
    {
      // Populate the map
    }
    return s_myMap;
  }
};
它适用于
MyClass
的外部客户端,但不会阻止内部类成员在初始化
private
映射之前直接访问该映射

为了解决这个问题,我正在考虑使映射成为getter方法的本地映射:

class MyClass
{
public:
  static const MapType& getTheMap()
  {
    static MapType s_myMap;
    if (s_myMap.empty())
    {
      // Populate the map
    }
    return s_myMap;
  }
};

这是一个好主意,还是有更好的方法来实现这一点?

您可以为此集合声明一个类并在构造函数中填充它。

如果在全局/
命名空间
范围中未调用
MyClass::getTheMap()
,这样,您就不必担心在初始化数据成员之前正在使用
静态
数据成员

但是,如果在全局/
命名空间
范围中使用了上述
静态
方法
gethemap()

SomeGlobal object = MyClass::getTheMap();

那么您当前的方法似乎很好。

将static移到函数中可以解决任何顺序的问题 初始化问题,但它可能会给您留下 毁灭一号。在许多情况下,最好使用指针和 动态分配,使地图永远不会被破坏

至于初始化它,我经常使用两个迭代器构造函数,所以 我可以使地图本身保持恒定。为此,只需定义一个
struct
带有转换运算符,类似于:

struct MapInitData
{
    char const* key;      //  Or whatever type is needed.
    char const* value;    //  Or whatever type is needed.
    operator MapType::value_type() const
    {
        return MapType::value_type( key, value );
    }
};

MapInitData const mapInitTable[] =
{
    { "key1", "value1" },
    //  ...
};

MapType const ourMap( begin( mapInitTable ), end( mapInitTable ) );

为了线程安全,函数“getTheMap”中应该有一个锁。将其移动到函数的本地位置是一个好主意

我认为这与drdobbs的文章“C++和双重检查锁定的危险”类似。在这里,他介绍了不同类型的singleton和其他threadsafety模式的用例和安全性


至于销毁,您需要销毁它吗?

将静态文件移到函数中是个好主意。只要没有其他静态对象初始化调用过
getTheMap
,就可以了。映射是动态初始化的吗?如果没有,您可以在初始值设定项中填充它(前提是您有一个最新的编译器)。@KerrekSB它是静态初始化的。为了验证我是否理解您的意思,您是否建议将
//填充映射所隐含的代码移动到一个单独的初始化方法(比如
initialiseMap()
),然后通过
MapType MyClass::s_myMap=initialiseMap()
)初始化映射?@atkins:我只需编写
常量MapType MyClass::s_myMap{1,“Jim”}、{2,“Jane”}、{3,“Joseph”};
作为初始值设定项,没有单独的函数来执行填充。@KerrekSB唉,我的编译器似乎不支持这种语法(我们被困在MSVC 2003上)。我得到
错误C2470:'MyClass::s_myMap':看起来像一个函数定义,但没有正式的参数列表;跳过明显的正文。
。不过谢谢你的想法!我对“初始化”这个词有点不太熟悉“。我在这里的意思是,在访问地图之前,应该使用一组条目填充地图。使用
MapType MyClass::s_myMap=MapType()
@atkins将数据成员初始化为一个更准确的空映射:如果您没有首先进入未定义的行为,那么
gethemap()
将正确设置条目。问题是,使用全局静态变量很容易陷入未定义的行为。这很好-我真的很想让map
const
,但我认为我不能。我讨厌这个建议(关于指针和动态分配)。销毁顺序问题很容易解决@LokiAstari我看不出那里的代码解决了什么问题。销毁顺序仅在对象的特定子集内排序,如静态声明的子集。假设您有一个
静态std::auto_ptr
,并且在构建之后很久,您将其重置为指向一个在其析构函数中使用此静态对象的对象。(这种情况并不常见——至少希望如此。但这种情况是可能的。)@James Kanze:静态存储持续时间对象的销毁顺序<代码>保证与构造顺序相反。我看不出你的例子(在评论中)有什么关系。@LokiAstari静态存储持续时间的对象的销毁顺序是有保证的。但并非所有对象都具有静态存储持续时间。考虑一些“静态AutoPPTR P”;静态对象o;int main(){p=auto_ptr new T(&o);}
。如果
T`使用在析构函数中传递给它的参数,会发生什么情况?