[C++] правила проектирования (было: деструкторы статических объектов)
Обратите внимание, что глобальных объектов тут вообще нет. Не надо мне тут про синглетоны.Ты крут, правда, похоже, что не понял этого
Твой код показывает, почему синглтоны — не панацея в общем случае
Просто надо переименовать f в GetA из примера DarkGray.
Но пенартур тоже прав в некотором роде: если зовешь из деструктора, надо быть аккуратным. Не только из-за глобальности, надо как минимум быть уверенным, что функция исключений не кидает, к примеру.
Вообще при обсуждении подобных проблем (обычно сразу после того, как потратил на отладку пару часов, ну или пару дней ) возникает желание сказать что-то типа "нахуй C++, лучше сразу не в ногу, а в голову выстрелить и на этот раз в прямом смысле". Успокаивает мысль, что люди и более неразрешимые проблемы решали
Также прошу заметить, что дело происходит в разных библиотекахО, это тоже момент. В разных библиотеках все проще: библиотечные статические объекты уничтожаются во время FreeLibrary. А если никто FreeLibrary явно не вызывал (а это случай load-time загрузки, т.е. когда линкуешься к "динамической" lib'е то после уничтожения всех статических объектов основного модуля.
Создаются, соответственно, во время LoadLibrary (глобальные объекты либо при вызове соответствующей функции (локальные статические, ну это как обычно). Причем в случае loadtime загрузки создаются до объектов основного модуля.
Это винда, в юниксовом программировании пока слабоват =)
Вот, придумал по дороге с работы, сейчас затестил. "Так и вышло".
В разных библиотеках все проще: ...
Вот, придумал по дороге с работы, сейчас затестил. "Так и вышло".
я правильно понял, что тебе пришла мысль "как это может быть", ты проверил ее на примере, все сошлось, и теперь ты утверждаешь, что так оно и должно быть всегда?
Можно, конечно, создать обёртку вокруг механизма подгрузки-выгрузки dll, но для этого нужно править стандартную библиотеку и смысла в этом нет.
я правильно понял, что тебе пришла мысль "как это может быть", ты проверил ее на примере, все сошлось, и теперь ты утверждаешь, что так оно и должно быть всегда?нет, я подумал о механизме уничтожения статических объектов в CRT, решил, что иходя из них так должно быть всегда. Пришел домой, проверил, так и вышло. Поэтому в винде так будет всегда.
calling g
starting g
create B
finishing g
finishing main
delete B start
starting f
create A
finishing f
delete B finish
delete A
как видно, А уничтожается в самом конце.
Для того, чтобы его сломать мне пришлось добавить вызов f в g после static B b; т.е.
void g
{
static B b;
f;
}
а тут уже не так:
calling g
starting g
create B
starting f
create A
finishing f
finishing g
finishing main
delete A
delete B start
starting f
finishing f
delete B finish
здесь начали исполнять f когда уже прибили A - нехорошо.
Кстати, по-поводу библиотек, здесь от них у меня поведение не зависело, хотя я пробовал линковаться как статически, так и динамически.
Я так понимаю, поскольку заранее нельзя узнать, нужно ли вообще вызывать деструкторы для статических объектов, то их порядок определяется в рантайме, судя по порядку вызова конструкторов?
(или я что-то не так понял):вызови f в main после создания B.
Я так понимаю, поскольку заранее нельзя узнать, нужно ли вообще вызывать деструкторы для статических объектов, то их порядок определяется в рантайме, судя по порядку вызова конструкторов?это да, но между библиотеками общий подрядок по крайней мере ms-компилятор поддерживать не пытается.
starting f
create A
finishing f
calling g
starting g
create B
finishing g
finishing main
delete B start
starting f
finishing f
delete B finish
delete A
Как видно, A прибили также в самом конце.
я там обновил пост
Ок, если в main идёт g; f; то плохо, да. Но это по сути то же, что в g вызвать f
Там гарантированный пиздец, а тут — как повезет (вызовут g где-нибудь или нет). Прикинь, у тебя программа, и она падает в конце работы только если ты вызваешь в каком-то месте какую-то функцию, иначе работает прекрасно. И даже если падает, то до падения работает прекрасно.
Оставить комментарий
Realist
Поскольку в соседней ветке больно много ответов и большинство их них не на тот вопрос, я бы хотел конкретизировать.Первый программист пишет библиотеку и предоставляет клевый класс А.
Второй программист пишет удобную функцию f:
Третий программист использует это дело в своем мега-классе B
Наконец, четвертый программист берет класс B и делает статический объект
Все это не работает, поскольку к моменту уничтожения B b статический объект A a уже уничтожен. Обратите внимание, что глобальных объектов тут вообще нет. Не надо мне тут про синглетоны. Также прошу заметить, что дело происходит в разных библиотеках и реализации классов и функций вообще могут быть скрыты, библиотеки поставляются в бинарном виде. Вопрос. Кто из программистов и какое правило (принцип) проектирования нарушил?
Если я правильно понял ответы именно на эти вопросы, то вот что получается (пусть авторы меня поправят):
penartur2 полагает, что нефиг из деструктора звать f. Третий программист должен был убедиться, что код у f простой и без подводных камней.
указывает, что нефиг писать static до тех пор, пока не обеспечил нужное время жизни. Второй и четвертый программисты — лопухи.
Mike тоже винит тех, кто засунул под static'и сами объекты, а не на указатели.