开发者

C++ string constants and static variable initialization (or just use macros?)

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?


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";


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;
}
}


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜