констант — с ++ статический порядок инициализации фиаско

В настоящее время я изучаю C ++, и у меня возникли некоторые проблемы.

Я разработал программу, используя много #define, но я хотел бы использовать static const вместо этого (столкновение / тип / границы …).

Итак, теперь у меня есть что-то вроде:

file1.hpp

 class A {
public:
static const std::string MY_CONST_VAR;
};

file1.cpp

 const std::string A::MY_CONST_VAR = "some string";

file2.cpp

 static std::string arrayOfString[] = {
A::MY_CONST_VAR,
...
};

Мой код компилируется без предупреждений / ошибок (компилируется с -W -Wall -Wextra -Werror flags).

Тем не менее, когда я пытаюсь запустить его, это приводит к segfault.

Я запустил его с помощью valgrind, и он дал мне следующий вывод:

==11239== Invalid read of size 4
==11239==    at 0x5F525CB: std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(std::string const&) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.19)
==11239==    by 0x40D076: _GLOBAL__sub_I__ZN16GraphicInterface13DEFAULT_WIDTHE (GraphicInterface.cpp:42)
==11239==    by 0x51AC7C: __libc_csu_init (in /home/simon/PSU_2013_zappy/gui/gui_zappy)
==11239==    by 0x66D8E54: (below main) (libc-start.c:246)
==11239==  Address 0xfffffffffffffff8 is not stack'd, malloc'd or (recently) free'd

Таким образом, segfault происходит во время создания экземпляра arrayOfString. Я думаю, что проблема в том, что arrayOfInt размещается перед константой. Но в этом случае возможно ли использовать статический констант для этой цели?

Я не знаю, как исправить эту проблему.
Я делаю это неправильно? Есть ли лучший способ сделать это? Как решить эту проблему?

3

Решение

Обычный обходной путь для проблем static-init-fiasco заключается в том, чтобы обернуть static в функцию, потому что переменные внутри функций не имеют своих инициализаторов, оцененных, пока функция не будет вызвана.

Это не так просто, когда это массив, длина которого определяется количеством инициализаторов. Тем не менее, IMHO, это плохой дизайн для доступа к глобальному массиву в стиле C: либо вы должны загрязнять свой код проверками диапазона каждый раз, когда вы используете массив, либо вы рискуете сделать доступ за пределы допустимого; и ошибки, связанные с массивом, являются одними из самых сложных ошибок для отладки во время выполнения.

Лично я бы заменил код на:

std::string &lookup_string(size_t n)
{
static std::string arrayOfString[] = { A::MY_CONST_VAR(), .... };

if ( n >= dimof(arrayOfString) ) throw....
return arrayOfString[n];
}

А также в другом файле, если constexpr недоступен:

std::string MY_CONST_VAR() { return "some string"; }

Теперь нет статичных фиаско.

NB. Я предполагаю, что вы хотите доступ к записи arrayOfString, так как вы не объявили это const, Если предполагается, что они предназначены только для чтения, могут быть сделаны дальнейшие улучшения.

3

Другие решения

Благодаря комментариям я наконец решил проблему с помощью constexpr ключевое слово.

Это дает мне следующий рабочий код:

file1.hpp

class A {
public:
static constexpr char MY_CONST_VAR[] = "some string";
};

file1.cpp

const char A::MY_CONST_VAR[];

file2.cpp

static std::string arrayOfString[] = {
A::MY_CONST_VAR,
...
};
2

По вопросам рекламы [email protected]