【问题标题】:Static members erroneously initialized as empty strings静态成员错误地初始化为空字符串
【发布时间】:2018-05-09 14:58:21
【问题描述】:

我有三个文件:

api.h:

class HttpApi{
 public:
    static bool postData(string json);

 private:
    static  string remoteHost;
    static  string port;
    static  string url;
};

api.cpp:

string HttpApi::remoteHost = Config::getInstance().getRemoteServer();
string HttpApi::port = Config::getInstance().getPort();
string HttpApi::url="/api/miner";

bool HttpApi::postData(string json)
{
    //Here I print Config::getInstance.getRemoteServer(), the value is correct set here

    cout<<"Start resolve "<< remoteHost<<"   "<<port<<endl;
    cout<<"Succeed in resolving "<<endl;

}

最后:

int main(int argc, char** argv)
{
    Config&  config = Config::getInstance();
    cout<<"Start loading configuration "<<endl;
    config.loadConfig("config.ini");

    HttpApi::postData("hello world");
}

我的问题是remoteHostport两个成员的初始化无效:在运行时,都是空的。

这里的Config 是一个单例类,它从config.ini 中读取值。它有一些成员,例如remoteHostport

为什么两个静态成员都是空的,我该如何解决?

【问题讨论】:

  • Static Initialization Order Fiasco,也许?您还没有显示Config 的代码。
  • HttpApi::remoteHostHttpApi::port 的初始化可能发生得太早,那时 Config::getInstance().getRemoteServer() 会因任何原因返回并为空字符串。先检查一下。
  • 静态成员对象的初始化很大程度上取决于整个事物的编译方式。标准说的第一件事是:静态成员按其定义的顺序进行初始化,而不是按声明的顺序初始化。标准规定的第二件事是:静态初始化可以在第一次使用类的任何对象或函数之前发生。
  • 这可能会有所帮助:stackoverflow.com/a/1008289/3807729

标签: c++ initialization static-members


【解决方案1】:

由于您没有提供Minimal, Complete, and Verifiable example,因此只能猜测会发生什么。

首先,类的静态数据成员在程序的最开始以未指定的顺序初始化,然后调用main()1。这意味着

string HttpApi::remoteHost = Config::getInstance().getRemoteServer();
string HttpApi::port = Config::getInstance().getPort();

之前评估
config.loadConfig("config.ini");

其次,如果我们假设Config::getInstance() 在调用任何loadConfig 之前返回一个默认构造的实例,并且如果我们还假设默认构造的Config 只是一个空字符串的集合,那么我们可以肯定地说,HttpApi::remoteHostHttpApi::port 将从空字符串初始化。

最后,一个可能的解决方案是删除反模式 Singleton is,或者为HttpApi 定义一种使用已加载配置的方式:

void HttpApi::load(Config const& conf) // obviously declared as static
{
    remoteHost = conf.getRemoteServer();
    port       = conf.getPort();
}

int main(int argc, char** argv)
{
    Config& config = Config::getInstance();
    std::cout << "Start loading configuration\n";
    config.loadConfig("config.ini");
    HttpApi::load(config);
    HttpApi::postData("hello world");
}

1)这并不完全正确,对于好奇的读者:

[class.static.data]/6

静态数据成员的初始化和销毁​​与非局部变量完全一样([basic.start.static][basic.start.dynamic][basic.start.term])。

[basic.start.dynamic]/4

具有静态存储时长的非局部非内联变量的动态初始化是在main的第一条语句之前排序还是延迟,由实现定义。

【讨论】:

  • 我认为您的猜测比我对“惨败”的建议更可能是正确的。但正如你所说,我们所能做的就是猜测。
  • 谢谢。我没有注意到静态成员初始化的顺序。我将更改我的代码
  • @FredLarson OP,只用几行代码,就提供了一个森林的危险信号;)
  • 快速的解决方法是将静态成员包装在静态成员函数中。因此,成员在第一次调用函数时被初始化。
  • @ArchieYalakki +1 但这会改变变量的可见性。如果这是可以接受的,这是一个好的解决方法。
猜你喜欢
  • 1970-01-01
  • 2017-03-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多