2

I am writing a library and wanted to be as C++ centric as possible, remembering the old adage "Macros are evil".

In a source file, I had the following definitions:

const std::string DATA_DIR_ENV_STR = "DATADIR"
const std::string DFLT_DATA_DIR =  "../data"

/*
#define DATA_DIR_ENV_STR  "DATADIR"
#define DFLT_DATA_DIR  "../data"
*/


std::string getRootDirectory()
{
    char * datastr_ = getenv(DATA_DIR_ENV_STR);

    if (datastr_)
        return std::string(datastr_);
    return DFLT_DATA_DIR;
}

// Header file

std::string getRootDirectory();

I then had a singleton class that was initialized like this:

bool mySingleton::inited = mySingleton::initialize();

bool mySingleton::initialize(){
   std::string rootdir = getRootDirectory(); // <-SEGV when using const std::string
}

The library compiled fine, but when I linked an application to it, the app always SEGV'd. I used gdb to track down the problem and to my shock/horror, the string variables DATA_DIR_ENV_STR and DFLT_DATA_DIR had not yet been initialized when they were been accessed during the static variable initialization.

In the end I simply used macros to get around the issue. BUT, I can't help wondering, is this a variation of the 'static variable initialization fiasco'?. Is there another way to resolve this without using macros?

1
  • 1
    If you use a Singleton, then you get what you pay for. Commented Feb 7, 2011 at 16:44

3 Answers 3

3

Yes, this is the static initialization fiasco biting your behind.

A way to avoid it is the "construct on first use" idiom (brain-compiled code):

// In the header
class mySingleton {
    private:
        static mySingleton *s_instance;
        mySingleton();
    public:
        mySingleton &instance() {
            if (!s_instance)
                s_instance = new mySingleton();
            return *s_instance;
        }
};

// And in the source file...
mySingleton *mySingleton::s_instance;

However, in the case of string constants, you can also get away with simple char pointers:

static char const *const DATA_DIR_ENV_STR = "DATADIR";
static char const *const DFLT_DATA_DIR = "../data";
Sign up to request clarification or add additional context in comments.

Comments

3

It is a static initialisation issue, as you suspect.

I assume you use .c_str() in your getenv clause.

You could use const char * const rather than std::string in your statics.

namespace {
/*static*/ const char * const DATA_DIR_ENV_STR = "DATADIR";
/*static*/ const char * const DFLT_DATA_DIR = "../data";
}

Note use of anonymous namespace is generally preferred now to static.

Your other option would be a function that returned them thus:

namespace {
const std::string & DATA_DIR_ENV_STR()
{
  static std::string s("DATADIR");
  return s;
}

const std::string&  DFLT_DATA_DIR()
{
  static std::string s("../data");
  return s;
}
}

Comments

2

It is indeed a manifestation of that. See http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 for more information (and below for solutions).

EDIT: Note that if you can redesign so that you don't need a singleton that will automatically fix the problem.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.