const variables in header file and static initialization fiasco

Hanno S. picture Hanno S. · Jan 26, 2011 · Viewed 37.8k times · Source

After reading a lot of the questions regarding initialization of static variables I am still not sure how this applies to const variables at namespace level.

I have kind of the following code in a header file config.h generated by the build script:

static const std::string path1 = "/xyz/abc";
static const std::string path2 = "/etc";

According to what I have read the static keyword is not necessary, even deprecated here.

My Question: Is the code above prone to the static initialization fiasco?

If I have the following in a header file myclass.h:

class MyClass
{
public:
    MyClass(const std::string& str) : m_str(str) {}
    std::string Get() const { return m_str; }

private:
    std::string m_str;
}

const MyClass myclass1("test");

Will this pose any problems with static initialization?

If I understood right, due to const variables having internal linkage there should be no problem in both cases?

Edit: (due to dribeas answer)

Maybe I should mention that I am interested in use cases like:

In main.cpp:

#include <config.h>
#include <myclass.h>

std::string anotherString(path1 + myclass1.Get());

int main()
{
    ...
}

Another question regarding this use case: Will the compiler optimize away path2 in this case?

Answer

Philipp picture Philipp · Jan 26, 2011

Your first definition places path1 in each compilation unit that includes config.h. To avoid this, don't define variables in header files. Usually you'd declare the variables in the header as extern:

extern const std::string path1;
extern const MyClass myclass1;

and define them in a translation unit, e.g. config.cpp:

const std::string path1 = "/xyz/abc";
const MyClass myclass1("test");

Sometimes you need a constant variable that is usable only from one translation unit. Then you can declare that variable at file scope as static.

static const std::string path1 = "/xyz/abc";

static is not deprecated any more. static and extern are sometimes implied, but I always forget where and how, so I usually specify them explicitly for all namespace-level variables.