使用静态初始化的副作用进行一次性初始化

时间:2012-05-07 16:31:01

标签: c++ namespaces initialization shared-libraries

我想在共享库中初始化一些查找表,我想看看这是否是一种有效的方式,如果它继续在更多的库中使用它我将要编写。

typedef std::map<std::string, int> NAME_LUT;
NAME_LUT g_mLUT;
namespace
{
    bool OneTimeInit() 
    {
        ::g_mLUT.insert(NAME_LUT::value_type("open",          1));
        ::g_mLUT.insert(NAME_LUT::value_type("close",         2));
        return true;
    }
    bool bInit = OneTimeInit(); // Just to make initialization happen
}

它似乎在Visual Studio和gcc(Linux)上都能正常工作。只有gcc抱怨bInit没有在任何地方使用。

  1. 是否可能优化初始化(bInit未使用),或语言不允许(由于副作用)。
  2. 它确实看起来像处理一次性初始化的良好的跨平台方式,但我不确定这是否是最好的方法。
  3. OneTimeInit声明为静态是否有意义? (即使用static bool OneTimeInit() {...}),或仅使用命名空间是使其对此编译单元唯一的更好方法

4 个答案:

答案 0 :(得分:7)

我不太喜欢使用静态存储的变量的想法,但如果你打算这样做,你可以通过编写一个初始化你的对象的函数来实际简化代码:

typedef std::map<std::string, int> NAME_LUT;
namespace {
   NAME_LUT create_lut() {
        NAME_LUT table;
        table.insert(NAME_LUT::value_type("open",          1));
        table.insert(NAME_LUT::value_type("close",         2));
        return table;
   }
}
NAME_LUT g_mLut = create_lut();

请注意,这有所有常见的初始化顺序问题(跨越不同的翻译单元,特别是动态库)

答案 1 :(得分:3)

是的,这是合法的,但既然你提到它在图书馆,你必须确保你创建的翻译将被链接:

How to force inclusion of "unused" object definitions in a library

答案 2 :(得分:1)

如果你有C ++ 11初始化列表,这对你有用吗?

NAME_LUT g_mLUT = { {"open", 1}, {"close", 2}, };

答案 3 :(得分:0)

如果bInit得到优化(可能,特别是如果您的lib获得dlopen),则初始化代码将无法运行。

让用户在理智的地方(在main启动后)对您的图书馆进行设置调用是否有问题?这样做可以消除代码中出现的许多可能的难以调试的初始化错误序列之一的可能性。 如果这不是一个选项我真的建议将init隐藏到一个静态本地的函数调用中,如下所示:

typedef std::map<std::string, int> NAME_LUT;
namespace
{
    bool OneTimeInit(NAME_LUT& mLUT) 
    {
        ::mLUT.insert(NAME_LUT::value_type("open",          1));
        ::mLUT.insert(NAME_LUT::value_type("close",         2));
        return true;
    }

    NAME_LUT& get_global_mLUT()
    {
        static NAME_LUT g_mLUT;
        static bool bInit = OneTimeInit(g_mLUT); // Just to make initialization happen
        return g_mLUT;
    }
}