Статические данные в библиотеках только заголовков
Я разрабатываю библиотеку, которая будет состоять только из файлов заголовков. Пока что он содержит только классы, которые были в порядке. Тем не менее, я пришел к тому моменту, когда мне нужно иметь доступную в библиотеке доступную неизменную информацию в библиотеке (то есть, а не данные экземпляра экземпляра) для реализации некоторых функций. Вы, очевидно, не можете просто помещать глобальные данные в заголовочные файлы, иначе вся единица компиляции, в которой #include
заголовок будет иметь определение для символа, и вы получите несколько ошибок определения во время ссылки.
Кажется, я нашел обходное решение, которое позволяет мне статические данные в классе, не добавляя блок компиляции в библиотеку, просто добавляя переменную a static
в функцию и возвращающую указатель на эти данные:
class StaticData {
public:
void doSomething() { /* this uses getData */ }
void doSomethingElse() { /* this does too */ }
private:
static int* getData() {
static int array[] { 1, 2, 3, 4 };
return array;
}
};
Это работает нормально, но я должен признать, что я не знаю, что происходит с функциями static
в inline
в файлах заголовков. Мне интересно, есть ли у этого "взлома" какие-либо непредвиденные последствия, такие как каждый блок компиляции, который #include
этот заголовок получает свою собственную версию array
. Как и где компилятор решил поставить его?
Также следует отметить, что я не использую это для реализации синглтон-антипаттерна или чего-то еще. Я просто использую его для хранения данных, которые нужно использовать нескольким функциям (поэтому он не может быть static
только в функции, которая его использует, но даже если бы это было так, что бы подсказывало тот же вопрос).
Ответы
Ответ 1
Это хорошо. Он гарантировал, что будет только одна копия array
, если функция имеет внешнюю связь, что и делает. В стандарте С++ говорится:
7.1.2/4 Статическая локальная переменная во внешней встроенной функции всегда относится к одному и тому же объекту.
Ответ 2
Другой подход...
template<typename> class ArrayData {
friend class ClassWithArray;
static int array[4];
};
class ClassWithArray :
ArrayData<ClassWithArray>
{
public:
void doSomething() {
/* this uses getData */
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 4;
}
void doSomethingElse() {
/* this does too */
array[0] = 4;
array[1] = 3;
array[2] = 2;
array[3] = 1;
}
};
int ArrayData<ClassWithArray>::array[4] = { 1, 2, 3, 4 };
общая реализация
template<typename T> class ArrayDataT
{
friend T;
static int array[4];
};
template<typename T>
int ArrayDataT<T>::array[4] = { 1, 2, 3 ,4 };
class DerivedFromArrayDataT :
ArrayDataT<DerivedFromArrayDataT>
{
};