Классы со статическими элементами, содержащими статические элементы в переполнении стека

У меня есть класс, который содержит статический член ‘obj’. Статический член класса obj сам содержит статический член (который является классом мьютекса).

Теперь, когда моя программа завершает работу, происходит сбой. Это происходит, когда статический объект obj разрушается. Деструктор obj вызывает свой статический член (мой собственный тип мьютекса, следующий за идиомой RAII, для разрушения нижележащих низкоуровневых объектов). К сожалению, этот элемент уже был уничтожен, поскольку порядок инициализации (-> противоположный порядок деструктора) статических объектов не определен.

Как выжить от этого чисто? Я удивлен, что это случалось не чаще. Похоже, вообще опасно иметь статические не POD-члены. Особенно, если вы не знаете их внутреннюю структуру.

1

Решение

Если вы делаете их static тогда внутри функций вы будете располагать их время жизни в зависимости от того, кто вызвал функцию первым. Вот как синглтоны имеют тенденцию реализовываться.

foo& get_foo() {
static foo instance;
return instance;
}

bar& get_bar() {
static bar instance;
return instance;
}

Вы действительно лучше избегать статики.

0

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

Это распространенная ошибка при попытке избежать динамического распределения.

Чтобы избежать этой проблемы, я должен следовать шаблону «статических классов» — обычно статические данные принадлежат классу «менеджера» для экземпляров, которые не имеют статических данных. Инициализация статических данных затем обрабатывается явными вызовами инициализации, а уничтожение обрабатывается явными вызовами выключения класса менеджера, который имеет только статические данные и статические функции-члены.

вам, возможно, придется использовать новое или удалить и четко указывать, что вы делаете — в этом смысле вы сводите на нет преимущества автоматических механизмов, выполняющих работу за вас, но взамен вы получаете надежные и легко отлаживаемые процедуры инициализации и завершения работы.

этот подход создает, по сути, единичный объект, поэтому экземпляров класса менеджера не существует — в основном это набор статических данных и некоторые функции C с синтаксисом класса, обеспечивающие преимущества инкапсуляции (например, закрытые члены не доступны вне класса)

во многих случаях это также удобно для компилятора, так как он знает, где находятся все ваши данные и что с ними делать

0

Если вам нужен объект, который используется статическими объектами, в
конструктор или деструктор, как правило, лучше использовать
изменение синглтон модели. Это решает порядок
проблемы инициализации, и если вы все сделаете правильно, объект будет
никогда не разрушаться, поэтому не должно быть никакого порядка уничтожения
проблемы либо.

Поскольку ваше приложение явно многопоточное (так как у вас есть
мьютекс), вы должны принять обычные меры предосторожности, чтобы сделать
Поток объекта безопасен, обеспечивая инициализацию перед вводом
главный. Основная идея что-то вроде:

template <typename T, char const* id>
class StaticInstanceWrapper
{
static T* myObject;
public:
static T& instance();
};

template <typename T, char const* id>
T* StaticInstanceWrapper<T, char const* id>::myObject =
&StaticInstanceWrapper<T>::instance();

template <typename T, char const* id>
T& StaticInstanceWrapper<T>::instance()
{
if ( myObject == NULL ) {
myObject = new T;
}
return *myObject;
}

Затем вы определяете статический объект как static
StaticInstanceWrapper<Whatever> obj;
и получить к нему доступ как
obj.instance().someFunction(), а не просто
obj.someFunction() (который не скомпилируется, потому что obj не
иметь someFunction() членом).

Обратите внимание, что для каждого экземпляра StaticInstanceWrapper иметь
другого типа, и поэтому иметь уникальные статические члены, вы должны
вызвать отдельное создание шаблона. Вот почему мы
хе id аргумент шаблона; тип этого аргумента может
практически быть чем угодно, до тех пор, пока каждый экземпляр имеет
уникальный идентификатор. На практике, я бы, вероятно, использовал макрос для
определение, что-то вроде:

#define DEFINE_STATIC_INSTANCE_WRAPPER(type, name) \
char const PASTE(name, _Identifier)[] = STRINGIZE(name); \
StaticInstanceWrapper<type, PASTE(name, _Identifier)> name

Это гарантирует, что каждый экземпляр имеет уникальный идентификатор. (Если ты хочешь
чтобы полюбить, вы можете изуродовать __LINENO__ как хорошо, но
так как имя должно быть уникальным в любом случае, я сомневаюсь, что
это необходимо.)

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