Я наткнулся на довольно раздражающую проблему, связанную с тем, когда среда выполнения Visual C ++ разрушает мои объекты при выходе из программы.
У меня есть класс, который используется, чтобы убедиться, что ссылки на определенные состояния действительны. Мне нужно хранить состояния в течение неизвестного количества времени, и в течение этого времени состояние может быть уничтожено, и я не могу использовать shared_ptr
, Поэтому я использую
class MyClass
{
private:
static std::list<MyClass*> make_list();
static std::list<MyClass*> refed_list;
static void StateClosed(B* state);
public:
B* state;
MyClass(B* state);
virtual ~MyClass();
bool still_valid() const;
};
Каждый экземпляр MyClass
добавляет себя в refed_list
в своем конструкторе и удаляет себя в своем деструкторе. Если инкапсулированное состояние закрыто, MyClass
уведомляется и проверяет refed_list
для инкапсулирующего экземпляра и делает недействительным его указатель. Это не очень важно, важно то, что он использует static list
и он получает доступ к этому списку в конструкторе / деструкторе. Я инициализирую refed_list
в файле где MyClass
определено.
Теперь проблема .. Когда моя программа закрывается, среда выполнения очищается refed_list
в какой-то момент, и после этого он очищает случаи MyClass
зовет своих деструкторов. Затем они пытаются получить доступ refed_list
который уже был убран. Это приводит к тому, что мои итераторы неверны, и я получаю неопределенное поведение, в данном случае ошибка отладочного утверждения.
Есть ли способ обойти эту проблему? Я сомневаюсь, что могу указать, какие объекты заказа в разных единицах компиляции разрушены, но есть ли способ проверить, refed_list
все еще действует? На данный момент я проверяю, refed_list.size() == 0
и это похоже на работу, но поведение этого тоже не определено (я думаю?).
Вы всегда можете сделать refed_list
указатель, который инициализируется при запуске. Таким образом, он никогда не будет очищен. (И всякая память, которую она использует, будет восстановлена ОС при выходе из вашего процесса.)
Если это звучит как хак, чтобы обойти более глубокую проблему дизайна, то, вероятно, так и есть. 🙂
Я не думаю, что это правда:
Когда моя программа закрывается, среда выполнения очищает refed_list в некоторый момент, и после этого она очищает экземпляры MyClass, вызывая их деструкторы.
Среда выполнения, безусловно, очистит список, но не объекты в списке, потому что они являются указателями. Единственный способ сделать это — использовать класс интеллектуальных указателей, например shared_ptr. Тем не менее, если вы это сделаете, объекты будут пытаться получить доступ к списку во время его уничтожения, что, я не уверен, является неопределенным поведением, но оно, безусловно, кажется шатким.
Возможно, вам следует изменить дизайн, чтобы объекты не ссылались на список, в котором они хранятся, или, по крайней мере, для этого до список уничтожен (и под этим я подразумеваю, прежде чем list :: ~ list даже будет вызван).