2011-02-07 207 views
1

我正在寫一個庫,並希望儘可能以C++爲中心,記住舊的諺語「宏是邪惡的」。C++字符串常量和靜態變量初始化(或只是使用宏?)

在源文件中,我有以下定義:

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

//頭文件

std::string getRootDirectory(); 

我當時已經陷入這樣的初始化一個單例類:

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

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

庫編譯得很好,但是當我將應用程序鏈接到它時,應用程序始終是SEGV'd。我使用gdb來追蹤這個問題,並且發現我的震驚/恐怖,字符串變量DATA_DIR_ENV_STR和DFLT_DATA_DIR在靜態變量初始化期間被訪問時尚未初始化。

最後我簡單地用宏來解決這個問題。但是,我不禁想知道,這是'靜態變量初始化失敗'的變體嗎?有沒有另一種方法來解決這個問題,而不使用宏?

+1

如果你使用一個單身,那麼你得到你所支付的。 – Puppy 2011-02-07 16:44:14

回答

2

是的,這是靜態初始化失敗咬你的背後。

,以避免它是「構建在第一次使用」成語(腦編譯的代碼)的一種方式:

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

然而,在字符串常量的情況下,還可以擺脫簡單char指針:

static char const *const DATA_DIR_ENV_STR = "DATADIR"; 
static char const *const DFLT_DATA_DIR = "../data"; 
3

這是一個靜態初始化問題,正如您懷疑的那樣。

我假定你在你的getenv子句中使用.c_str()。

你可以在靜態中使用const char * const而不是std :: string。

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

注意現在使用匿名命名空間通常首選靜態。

你的另一種選擇將是返回他們這樣一個功能:

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