0

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

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声明为静态有意义吗?(即 use static bool OneTimeInit() {...}),或单独命名空间是使其对这个编译单元唯一的更好方法
4

4 回答 4

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();

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

于 2012-05-07T16:39:46.337 回答
3

是的,这是合法的,但由于您提到它在图书馆中,因此您必须确保您正在创建的翻译将被链接:

如何强制在库中包含“未使用”的对象定义

于 2012-05-07T16:34:40.600 回答
1

如果您有 C++11 初始化程序列表,这对您来说会更好吗?

NAME_LUT g_mLUT = { {"open", 1}, {"close", 2}, };
于 2012-05-07T16:49:33.270 回答
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;
    }
}
于 2012-05-07T17:00:30.307 回答