Строковые константы C ++ и инициализация статических переменных (или просто использовать макросы?) - PullRequest
1 голос
/ 07 февраля 2011

Я пишу библиотеку и хотел быть как можно более ориентированным на 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 еще не были инициализированы, когда к ним обращались во время инициализации статической переменной.

В конце концов, я просто использовал макросы, чтобы обойти эту проблему. НО, я не могу не задаться вопросом, это разновидность «фиаско инициализации статической переменной»? Есть ли другой способ решить эту проблему без использования макросов?

Ответы [ 3 ]

3 голосов
/ 07 февраля 2011

Как вы подозреваете, это статическая проблема инициализации.

Я предполагаю, что вы используете .c_str () в своем предложении getenv.

Вы можете использовать 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;
}
}
2 голосов
/ 07 февраля 2011

Да, это фиаско статической инициализации, кусающее вас за спину.

Способ избежать этого - идиома «конструкция при первом использовании» (скомпилированный мозгом код):

// 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";
2 голосов
/ 07 февраля 2011

Это действительно проявление этого. См. http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.14 для получения дополнительной информации (и ниже для решений).

РЕДАКТИРОВАТЬ: обратите внимание, что если вы можете изменить дизайн так, чтобы вам не нужен единый, который автоматически решит проблему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...