Я наткнулся на довольно неприятную проблему, связанную с тем, что среда выполнения Visual C++ разрушает мои объекты по мере выхода программы.Порядок уничтожения объекта 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
и, похоже, работает, но поведение этого тоже не определено (я думаю?).
Звучит как проблема с одноэлементным циклом. Я думаю, что Скотт Мейерс или Андрей Александреску написал кое-что об управлении ими тремя или так разными способами. Финикс Синглтон может оказаться в вашем переулке. –
И это одна из многих причин, по которым я запрещаю экземпляры глобального класса в моей команде. Потому что порядок уничтожения объекта во время выхода программы является либо недетерминированным, либо просто трудно получить право. В любом случае, можете ли вы просто запустить функцию очистки приложения до того, как WinMain/main вернется?Или еще лучше, если эти деструкторы не делают что-то критически важное, почему бы просто не допустить, чтобы все объекты протекали при завершении работы приложения? – selbie
@selbie Я начинаю думать, что это хорошая идея. Причина, по которой я делаю это, заключается в том, что мне нужно сохранить объект, который может быть признан недействительным до его использования, и я не могу использовать 'shared_ptr', поэтому мне нужно каким-то образом уведомлять объекты, если они действительны или нет. Поэтому мне нужно отслеживать объекты, и поэтому у меня есть статический список. Но да, если я переписал несколько вещей, я могу вручную закрыть его, что должно решить мою проблему. Присоединение к процессам иногда затрудняет работу. – user1520427