2011-11-01 128 views
2

我有一个类,它包含一个静态成员,一个字符串映射到函数指针。该映射旨在用一组静态映射填充一次,并且不会随后进行修改。强制静态成员初始化

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

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; 
    } 
}; 

这是一个好主意,或者是有实现这一目标的一个更好的办法?

+0

将静态移动到函数是一个好主意。只要没有其他的静态对象初始化调用'getTheMap',你就没事。 –

+0

地图是否动态初始化?如果没有,你可以将它填充到初始化程序中(假设你有最近的编译器)。 –

+0

@KerrekSB它是静态初始化的。为了检查我已经理解了你,你是否建议将'//填充地图'所隐含的代码移动到一个单独的初始化方法(例如'initialiseMap()'),然后通过'MapType MyClass :: s_myMap = initialiseMap()'? – atkins

回答

1

将静态函数移入该函数将解决初始化问题的任何顺序 ,但它可能会使您的订单损坏一个,即 。在许多情况下,最好使用指针和动态分配,以便映射永远不会被破坏。

至于初始化它,我经常使用两个迭代器的构造函数,所以我可以使这个映射本身为const。要做到这一点,只是定义 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)); 
+0

这真是太棒了 - 我真的想把地图制作成'const',但是我不认为我能够做到。 – atkins

+0

我讨厌这个建议(关于指针和动态分配)。销毁问题的顺序很容易解决。 http://stackoverflow.com/questions/335369/finding-c-static-initialization-order-problems/335746#335746。 –

+0

@LokiAstari我没有看到那里的代码解决任何问题。销毁顺序仅在特定的对象子集内排序,如静态声明的那些。假设你有一个'static std :: auto_ptr ',并且在它的构造很久之后,你重置它以指向一个在它的析构函数中使用这个静态对象的对象。 (这种情况并不常见---至少有希望,但这是可能的) –

1

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

+0

是的,这也可以 - 谢谢。 – atkins

1

如果在全局/ namespace范围内没有调用MyClass::getTheMap(),那么在初始化之前您不必担心使用的数据成员static

不过,如果上述static方法getTheMap()在全球/ namespace范围使用:

SomeGlobal object = MyClass::getTheMap(); 

那么你目前的做法似乎是罚款。

+0

我对“initialise”一词有点宽松。我的意思是,在访问之前,地图应该填入一组条目。数据成员使用'MapType MyClass :: s_myMap = MapType()',以更精确的方式初始化为空映射。 – atkins

+0

@atkins:如果你还没有首先陷入未定义的行为,那么getTheMap()会正确地设置条目。问题在于,使用全局静态变量很容易陷入未定义的行为。 –

0

你的函数“getTheMap”应该有一个线程安全中有一个锁。将其移到本地功能是一个好主意。

我认为这与drdobbs文章“C++和双重检查锁定的危险”http://drdobbs.com/cpp/184405726类似于这个问题。在这里他通过使用案例和不同类型的单身人士安全其他模式与threadsafety。

至于破坏,你需要摧毁它吗?