Reputation: 3927
Running c++ on Ubuntu.
in configuration.h file i have this (global):
static const string APP_CONFIG_FILE_NAME = "cfg";
in my configuration.cpp (which is singleton by the way, so load configuration is called by constructor of Configuration) i do this:
void Configuration::loadConfiguration() {
cout<< "config file name " << APP_CONFIG_FILE_NAME.data();
load();
}
The load configuration will be called from another global: (this is the key point for the failure)
Timer t(Configuration::Instance()->timeout);
i see that the cost string is not initialized (empty). If i replace the string with char* its initialized in my expected order.
However on another program the same classes for configuration work, so i dont know the problem.
There is another question but not the same since there its not a global.
Upvotes: 4
Views: 4081
Reputation: 104708
It gets initialized, of course. However, it is likely being initialized in the order you don't want/expect it initialized in.
Specifically, it is probably not constructed by the time you use it because you use it during construction of another global.
Unfortunately, you don't have a good way to portably specify initialization order of global data. Initialization order among multiple files is not defined by the standard, although it is likely specified by your toolchain. Consequently, altering the order of compilation or building using another toolchain can result in a different initialization order. Search for "static initialization order fiasco" for more details.
One way to avoid this issue is to declare your static data in a function:
const std::string& AppConfigFileName() {
static const std::string name("cfg");
return name;
}
Although...I don't see why this must be static (the function above allows you to return by value -- no need for static). Plus, I don't see why this could not be a plain C string, since you just treat it as a C string in your config loader.
Upvotes: 10
Reputation: 154047
The key issue is when Configuration::loadConfiguration
is called. The
order of initialization between translation units is undefined, so
if Configuration::loadConfiguration
is called from the constructor of
a static object in another translation unit, the variable may not have
been constructed. In this particular case, the simplest solution is
just to change the type to char const[]
; this allows static
initialization, which occurs before any dynamic initialization. (Any
initialization which involves non-trivial constructors is dynamic.)
More generally, you could use the singleton pattern for the string.
Several other points are worth mentioning as well:
You've declared a static
instance of an object in a header file.
This means that every translation unit which includes the header file
will have a separate instance of the object. This is probably not a
good idea.
You output APP_CONFIG_FILE_NAME.data()
. This is simply the data in
the std::string
object—it is not guaranteed to be '\0'
terminated. When you need a '\0'
terminated string, you must use
std::string::c_str()
. (But in this case, you can just output the
std::string
. There's no need for any function call on it.)
Upvotes: 2