3

在 Ubuntu 上运行 c++。

在 configuration.h 文件中我有这个(全局):

static const string APP_CONFIG_FILE_NAME = "cfg";

在我的 configuration.cpp (顺便说一下,这是单例的,所以加载配置由 Configuration 的构造函数调用)我这样做:

void Configuration::loadConfiguration() {
    cout<< "config file name "  << APP_CONFIG_FILE_NAME.data();
        load();
}

加载配置将从另一个全局调用:(这是失败的关键点)

Timer t(Configuration::Instance()->timeout);

我看到成本字符串未初始化(空)。如果我用 char* 替换字符串,它会按我预期的顺序初始化。

但是在另一个程序上,相同的类用于配置工作,所以我不知道问题所在。

还有另一个问题,但不一样,因为不是全球性的。

4

2 回答 2

9

当然,它会被初始化。但是,它可能会按照您不希望/期望它初始化的顺序进行初始化。

具体来说,它可能在您使用它时尚未构建,因为您在构建另一个全局时使用它。

不幸的是,您没有一个很好的方法来可移植地指定全局数据的初始化顺序。标准未定义多个文件之间的初始化顺序,尽管它可能由您的toolchain指定。因此,更改编译顺序或使用另一个工具链构建可能会导致不同的初始化顺序。搜索“静态初始化订单惨败”了解更多详情。

避免此问题的一种方法是在函数中声明静态数据:

const std::string& AppConfigFileName() {
  static const std::string name("cfg");
  return name;
}

虽然......我不明白为什么这必须是静态的(上面的函数允许您按值返回 - 不需要静态)。另外,我不明白为什么这不能是普通的 C 字符串,因为您只是在配置加载器中将其视为 C 字符串。

于 2012-08-21T11:18:19.483 回答
2

关键问题是何时Configuration::loadConfiguration被调用。翻译单元之间的初始化顺序是未定义的,因此如果Configuration::loadConfiguration从另一个翻译单元中的静态对象的构造函数中调用,则该变量可能尚未构造。在这种特殊情况下,最简单的解决方案就是将类型更改为char const[]; 这允许静态初始化,这发生在任何动态初始化之前。(任何涉及非平凡构造函数的初始化都是动态的。)更一般地说,您可以对字符串使用单例模式。

其他几点也值得一提:

  • 您已经static在头文件中声明了一个对象的实例。这意味着每个包含头文件的翻译单元都会有一个单独的对象实例。这可能不是一个好主意。

  • 你输出APP_CONFIG_FILE_NAME.data(). 这只是std::string对象中的数据——保证会被'\0' 终止。当您需要一个'\0'终止的字符串时,您必须使用 std::string::c_str(). (但在这种情况下,您可以只输出 std::string. 不需要对其进行任何函数调用。)

于 2012-08-21T11:33:57.993 回答