LINUX.ORG.RU

Деструкторы не нужны (?)

 


0

5

Тут в соседней теме один анон сказанул следующее:

Дело не в том. Сишка, она про написание руками + можно навесит абстракций, аки глиб/гобджект. Кресты же — изначально нагромождение абстракций со строками, срущими в кучу, функциональными объектами, методами, вызывающимися неявно (например, деструкторы, на которые жаловался кармак) и проч

Собственно, хотелось бы поговорить о выделенном.

Антон прикрылся ссылкой, по которой про деструкторы я так ничего и не нашёл. Более того, в твиттере Кармака всё выглядит с точностью до наоборот — https://twitter.com/id_aa_carmack/status/172340532419375104

RAII constructor / destructor pairing and templates for type safe collections are pretty high on my list of C++ benefits over C

Кто прав? Кто виноват? И нужны ли в итоге C++ деструкторы?

Ответ на: комментарий от dzidzitop

Да уж, прям образец стиля exception-safe программирования.

 final AtomicReference<Throwable> buildFailureException = new AtomicReference<Throwable>();
...
buildFailureException.set(ex);

Что будет, если у вас в нескольких нитях исключения возникнут? Останется только одно из них?

for (int i = 0; i < threadsToCreate; ++i) {
            final Thread t = new Thread(parallelBuildWorker);
            threads[i] = t;
            t.start();
}

Что будет, если у вас на старте i-ой нити возникнет исключение?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Покажите код, плиз.

когда просят реализовать что-то подобное, то я всегда спрашиваю «как должна вести себя система, если что-то пошло не так в середине процесса?». пока мне не ответят, не приступаю к реализации. когда ответят - реализую так, как нужно. список файлов наверх я бы передавал как какой-нибудь std::vector. что внутри - зависит от задачи. наличие такого vector of errors было бы частью API. что делали б наверху с этим списком - меня внутри функции не колышет. что б делал я - то, что меня бы попросили реализовать. к тому времени все нужные flush(), close(), ~File() уже давно вызваны.

Во всех остальных случаях, если что-то пошло не так, следует дернуть rollback.

проблема только в том, что rollback вернёт ошибку, если, например, сеть упала. а на базе будет висеть незавершённая транзакция. а про это никто не узнает, кроме админа. конкретно я бы писал код в стиле

success = false;
try {
    /* code */;
    commit();
    success = true;
} catch (...) {
    if (!success) {
        rollback();
    }
    throw;
}

и точно не полагался бы на деструктор. первый вариант тоже не очень, ибо плюсовый код кидает исключения, поэтому можно где-то что-то недосмотреть.

dzidzitop ★★
()
Последнее исправление: dzidzitop (всего исправлений: 1)
Ответ на: комментарий от eao197

это message passing между потоками.

конкретно тут - весь процесс оборвётся (т.е. все потоки перестанут молотить задачи из пула после активной), а пользователь увидит одну ошибку из тех, которые оборвали процесс. что отвечает техзаданию, которое я сам себе поставил.

dzidzitop ★★
()
Ответ на: комментарий от eao197

А если разработчику знать об ошибке нужно, то почему же он не дернул rollback вручную?

Т.е. деструкторы не нужны в данном случае :-)

У разработчика полно возможностей сказать о том, что он хочет, в явном виде: хочет — дергает commit, хочет — дергает rollback. И получает при этом всю полноту власти и информации.

Т.е. деструкторы не нужны в данном случае :-)

А вот если что-то пошло не так, если разработчик — это анонимный смайлик с LOR-а, и не вызвал сам ни commit, ни rollback, то деструктор может попробовать подчистить ресурсы за этим интеллектуалом. Но без каких либо гарантий.

Польщён заботой, но в данном случае деструкторы и правда не нужны :-) Ч.т.д. :-)

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

Ты это сейчас не о любителях деструкторов? :-) Лол :-)

anonymous
()
Ответ на: комментарий от eao197

Что будет, если у вас на старте i-ой нити возникнет исключение?

вопрос хороший. возможно, будет утечка ресурсов. посмотрю. если так, то пофиксаю.

dzidzitop ★★
()
Ответ на: комментарий от dzidzitop

когда просят реализовать что-то подобное, то я всегда спрашиваю «как должна вести себя система, если что-то пошло не так в середине процесса?».

Прекрасно. Просто прекрасно.

Особенно вот это:

список файлов наверх я бы передавал как какой-нибудь std::vector.

Вот у вас на закрытии i-го файла возникла ошибка, вы пытаетесь добавлять его дескриптор в этот самый std::vector и ловите bad_alloc. Опс, как же так?!!

Или вы попытаетесь сначала преаллоцировать вектор? А потом закрывать файлы? Ануткать вы поймаете bad_alloc при этой преаллокации?

проблема только в том, что rollback вернёт ошибку, если, например, сеть упала. а на базе будет висеть незавершённая транзакция. а про это никто не узнает, кроме админа.

Ну и что сможет программа с этим сделать? Программа по какой-то причине завершается, откатывает незавершенную транзакцию, тут случается облом на rollback-е. Ну и что делать? Отсылать SMS в службу техподдержки?

В коде, который вы показали, есть нюанс: вы выпустите наружу исключение, связанное с rollback-ом. Это может быть совсем не то, что нужно прикладному коду.

Что будете делать?

eao197 ★★★★★
()
Ответ на: комментарий от dzidzitop

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

Ну как же так, вы тут критикуете C++ные деструкторы за потерю информации, а сами без зазрения совести делаете это и все нормально? Типа «отвечает техзаданию»?

Может пора уже крестик таки снять?

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Вот у вас на закрытии i-го файла возникла ошибка, вы пытаетесь добавлять его дескриптор в этот самый std::vector и ловите bad_alloc. Опс, как же так?!!

«всё уже изобретено.» vector<primitive_type>::reserve() прекрано будет работать там, где нужен nothrow код.

Ну и что сможет программа с этим сделать?

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

dzidzitop ★★
()
Ответ на: комментарий от eao197

я не критикую C++ деструкторы. я показываю, что они void ~Class(void) nothrow, а, значит, имеют ограниченную сферу применения.

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

dzidzitop ★★
()
Ответ на: комментарий от eao197

Транзакция — это такая штука, которая либо явным образом завершается успешно, либо же откатывается.

Это лишь в том случае, если на момент завершения транзакции не было ни одной ошибки :-) Если же таковая имелась, то COMMIT автоматом трактуется как ROLLBACK :-) На заметку ветерану C++, если что :-)

Соответственно, явно следует вызывать именно commit. Во всех остальных случаях, если что-то пошло не так, следует дернуть rollback.

Открыл Америку прям :-) Теперь расскажи про «такую штуку», как, например, курсор :-) Там есть только 2 варианта DECLARE (открыть) и CLOSE (закрыть) :-) Напиши как деструктор ~Cursor() :-)

anonymous
()
Ответ на: комментарий от eao197

В коде, который вы показали, есть нюанс: вы выпустите наружу исключение, связанное с rollback-ом.

этот нюанс уже давно будоражит умы программистов. на той же жабе сделали так, что все suppressed exceptions сохраняются внутри того эксепшина, который действительно идёт наверх. этот код иллюстративный. реальный код на реальной транзакции зависит от того, что за API предоставляет драйвер базы для C или C++

dzidzitop ★★
()
Ответ на: комментарий от DarkEld3r

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

Значит, bad_weak_ptr не правильно наследуется от std::exception :-) Должен тогда от std::logic_error :-) Ну ты понял :-)

С std::async хитрее, согласен. Хотя тоже можно обойти, ну или давай более конкретные случаи рассматривать.

Да что там рассматривать? :-) Стандартная библиотека полна исключений :-)

anonymous
()
Ответ на: комментарий от dzidzitop

обработка ошибок - непростая задача в принципе. к теме деструкторов не имеет отношения.

Все, на этом беседу можно заканчивать. Возвращайтесь, когда подучитесь.

eao197 ★★★★★
()
Ответ на: комментарий от dzidzitop

vector<primitive_type>::reserve() прекрано будет работать там, где нужен nothrow код.

Каким образом интересно? Ведь reserve сам бросает исключения.

DarkEld3r ★★★★★
()
Ответ на: комментарий от dzidzitop

проблема только в том, что rollback вернёт ошибку, если, например, сеть упала.

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

вообще какие-то жабопроблемы, характерные исключительно для жабы, где на каждое действие модно новый поток заводить и в нем все делать последовательно.

i36_zubov
()
Ответ на: комментарий от i36_zubov

ну ок, постучались туда еще секунд 5. и дальше что? если сети нет, ничего уже не сделать

веб-апликуха на пэхапэ и марсоход будут обрабатывать подобные ошибки по-разному.

у меня ответ простой - как захочет автор техзадания. код решает его проблемы, а не мои. в моей практике были такие варианты:

- повторная попытка сразу же

- повторная попытка с таймаутом, который растёт по степени двойки

- репорт ошибки в лог

- репорт ошибки в базу

- отсыл ошибки на систему мониторинга для админа

dzidzitop ★★
()
Последнее исправление: dzidzitop (всего исправлений: 1)
Ответ на: комментарий от DarkEld3r

ок, noexcept, не придирайся.

noexcept(false) тоже работает без гарантий вызова других деструкторов. так что это совсем не вариант в большинстве случаев.

dzidzitop ★★
()
Ответ на: комментарий от anonymous

Да что там рассматривать? :-) Стандартная библиотека полна исключений :-)

Ну я останусь при своём, слегка скорректированном мнении: большинство исключений можно избежать.

DarkEld3r ★★★★★
()
Ответ на: комментарий от dzidzitop

его нужно вызывать перед началом работы с файлами.

Да, но это не сильно спасает в рассматриваемой ситуации. Допустим, не удалось зарезервировать вектор. И что дальше? Не удалять файлы? Так себе решение, тем более, что возможна ситуация когда они все закроются без ошибок и вектор нам и не понадобится.

DarkEld3r ★★★★★
()
Ответ на: комментарий от dzidzitop

ок, noexcept, не придирайся.

Не придираюсь, просто уточняю. (:

С тем, что выброс исключений из деструкторов - ситуация очень редка согласен.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Допустим, не удалось зарезервировать вектор. И что дальше?

это гарантия (в представленном случае), что не будет bad_alloc посреди сбора всей информации что там свалилось. но в целом да - без транзакций обрабатывать пакетные задания боль и печаль.

dzidzitop ★★
()
Ответ на: комментарий от dzidzitop

в любом случае, проблемы сделать это в деструкторе нет никакой. можно сделать класс, который можно вставить в список без аллокации, и если он окуклился туда его и вставить в очередь на закрытие, куда потом заходить с визитами. можно сделать Transaction как smartpointer для какого-нибудь TransactionPrivate, который собственно и будет реальной транзакцией - никто же не говорил что задачу нужно сделать именно за один класс.

я не понимаю, о чем вообще тред. деструктор по определению уже окончательное действие. это проблема ну на полдня, если котиков смотреть - как сделать так, чтоб не зависало и при этом можно было выйти из скобок {} так чтоб все закрылось.

i36_zubov
()
Ответ на: комментарий от dzidzitop

Вы не поняли. У вас есть список из N файлов и вам нужно их все закрыть. А вот вектора для хранения незакрытых файлов нет. Если вы попытаетесь зарезервировать этот вектор перед процедурой закрытия, то можете словить bad_alloc. И что тогда?

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

eao197 ★★★★★
()
Ответ на: комментарий от dzidzitop

А у log_error прототип:

void log_error(const std::string & msg);

eao197 ★★★★★
()
Ответ на: комментарий от i36_zubov

теоретически всю программу можно написать в деструкторе. так что и так тоже можно делать. а насколько адекватно это - каждый решает сам.

понятно только то, что деструкторы и код с runtime errors в них - тема пикантная. примерно как голый new в конструкторах.

dzidzitop ★★
()
Ответ на: комментарий от eao197

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

если в ТЗ написано «закрывать все файлы, какие только возможны, по тем файлам, которые не были успешно обработаны, создать подробный отчёт ошибок», то так и буду делать - std::vector с reserve, а только потом открывать файлы. если можно игнорировать bad_alloc (некритичная задача), то так делать не буду, наверное. обработать N файлов - это и есть задача строк на 500 обычно - какая-нибудь регулярная задача для шедулера.

А у log_error прототип:

прототип void log_error(const char *) noexcept;

dzidzitop ★★
()
Ответ на: комментарий от dzidzitop

если в ТЗ написано «закрывать все файлы, какие только возможны, по тем файлам, которые не были успешно обработаны, создать подробный отчёт ошибок»

Правильно ли я понимаю, что постановщиком задачи вы сами никогда не выступали?

обработать N файлов - это и есть задача строк на 500 обычно - какая-нибудь регулярная задача для шедулера.

Ох, мать, мать, мать.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Правильно ли я понимаю, что постановщиком задачи вы сами никогда не выступали?

там, где выступаю я - вам не нравится моя постановка задачи.

когда пишу код «на дядю», то у «дяди» спрашиваю про corner cases. иногда говорят, как нужно, иногда мычат в ответ. в последнем случае передаю контекст ошибки выше. в конце концов идёт логирование куда-нибудь, а data consistency удовлетворяется по ситуации. с базой данных просто - rollback + контекст ошибки в большинстве случаев. с payment gateways гемор, у каждого свой. всё индивидуально.

dzidzitop ★★
()
Ответ на: комментарий от eao197

Ох, мать, мать, мать.

рад, что вам довелось создавать системы на миллионы строк кода, которые занимаются только тем, что обрабатывают N файлов. у меня как-то обычно маленькие подсистемы этим занимаются.

dzidzitop ★★
()
Ответ на: комментарий от DarkEld3r

Ну я останусь при своём, слегка скорректированном мнении: большинство исключений можно избежать.

Моё мнение не изменилось: C++ можно избежать :-)

anonymous
()
Ответ на: комментарий от anonymous

При таком дизайне класса Transaction

Смени дизайн :-)

anonymous
()
Ответ на: комментарий от dzidzitop

Попрошу код на 500 строк хотя бы для загрузки (по полному стандарту, а не с упрощениями, где то не поддерживается и сё) такой простой вещи, как .Obj файлов с 3D модельками и разумеется с материалами, текстурами, прозрачностями. Просто проще этого мне сложно что-то реальное придумать. Только не надо выносить структуру классов в которую будешь загружать данные в отдельную часть.

peregrine ★★★★★
()
Ответ на: комментарий от anonymous

Моё мнение не изменилось: C++ можно избежать :-)

Всего можно избежать.

DarkEld3r ★★★★★
()
Ответ на: комментарий от peregrine

конечно тут будет работать много больше кода, если включать код парсинга одного файла. в таком случае часто это больше 500 строк. устроит так?

dzidzitop ★★
()
Ответ на: комментарий от dzidzitop

там, где выступаю я - вам не нравится моя постановка задачи.

Ну давайте попробую вам еще раз объяснить. В общем случае встречаются ситуации, когда нужно сделать N действий подряд, каждое их которых может завершится ошибкой. Когда на i-ом действии ошибка случается, есть вопрос: что делать дальше? Вариантов немного:

- либо проигнорировать ошибку и продолжить выполнение оставшихся действий;

- либо прервать выполнение действий и заняться исправлением возникшей проблемы;

- либо сохранить описание ошибки, продолжить выполнение. Если в дальнейшем будут возникать новые ошибки, то вы накапливаете их в некотором контейнере.

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

Однако, в случае, когда работает деструктор, свободы выбора у нас нет. Может деструктор вызвался при раскрутке стека из-за исключения и мы не можем бросать свои исключения. Может деструктор вызвался из-за тогда, что приложение финиширует и у нас нет возможности выдерживать паузу и делать повтор.

Что и приводит к тому, что в деструкторе свободы нет. А вот возможности подчистить хвосты за собой есть. Пусть даже в процессе этой чистки информация о каких-то проблемах будет потеряна.

Так что использование деструктора для очистки ресурсов — это норма. И эта норма как раз является частью проблемы работы с ошибками. Поскольку вызов деструкторов при раскрутке стека из-за исключений (или даже из-за возврата кода ошибок) — это часть этой самой обработки ошибок.

А вот попытка затащить в деструктор кусок прикладной логики, вроде того, что если файл не закрылся, то нужно сделать 10 попыток с постоянно увеличивающейся паузой между ними, каждый раз записывая ошибку в лог, а затем отослать email на адрес службы техподдержки... Вот это уже маразм и непонимание того, для чего нужны деструкторы.

Поэтому когда вы говорите, что деструктор — это всего лишь некая noexcept-функция, то вы явно демонстрируете, что не понимаете этой относительно простой вещи.

eao197 ★★★★★
()
Ответ на: комментарий от eao197

Что и приводит к тому, что в деструкторе свободы нет. А вот возможности подчистить хвосты за собой есть. Пусть даже в процессе этой чистки информация о каких-то проблемах будет потеряна.

если всё равно, что будет с runtime error будь такой случится в деструкторе, то без проблем. я предпочитаю noexcept(false) код не вызывать в деструкторе, потому что это ненадёжно. кому нормально, что «в 99.9999% случаев ошибка не случится» - на здоровье.

сам деструкторы использую для очистки памяти, анлока мьютексов, отдачи сишных структур (iconv, например). т.е. того, что если и свалится, то только по причине ошибки в коде.

dzidzitop ★★
()
Ответ на: комментарий от dzidzitop

я предпочитаю noexcept(false) код не вызывать в деструкторе, потому что это ненадёжно. кому нормально, что «в 99.9999% случаев ошибка не случится» - на здоровье.

Ну вот, опять. Да чтож такое-то?

Допустим, есть у нас такая обертка над std::FILE:

class file_wrapper {
  std::FILE * f_{};
public :
  ...
  ~file_wrapper() {
    if(f_) try{ close(); } catch(...){}
  }
  ...
  void close() {
    if(EOF==std::fclose(f_)) throw std::system_error(...);
    f_ = nullptr;
  }
  ...
};
Что плохого в такого типа деструкторе?

eao197 ★★★★★
()
Ответ на: комментарий от DarkEld3r

Не вижу с этим проблем, если честно. Ведь и про исключения ему знать приходится.

Одно дело, когда деструктор кидает исключение «кончилось место на диске», а приложение определяет, что с этим делать. А другое — когда любой нетривиальный деструктор случайной ошибкой внезапно рушит систему. В идеале для деструкторов нужна система наподобие handler-bind в Common Lisp или даже лучше [гкд=https://msdn.microsoft.com/ru-ru/library/5hsw66as.aspx]On Error в Visual Basic.

можно ли тебе дурацкие вопросы про Racket позадавать? Через какой-нибудь гиттер/скайп/что-то ещё

Можно. Лучше в почту: kalimehtar@mail.ru

monk ★★★★★
()
Ответ на: комментарий от monk

А другое — когда любой нетривиальный деструктор случайной ошибкой внезапно рушит систему.

Покажите, пожалуйста, пример нетривиального деструктора.

eao197 ★★★★★
()
Ответ на: комментарий от utf8nowhere

у него аналог On Error.

Просмотрел краем глаза (в виде текста нет?). Не понял, в деструкторе этот его On_Error_на_макросах работает?

monk ★★★★★
()
Ответ на: комментарий от eao197

Покажите, пожалуйста, пример нетривиального деструктора.

QWidget::~QWidget()
{
    Q_D(QWidget);
    d->data.in_destructor = true;

#if defined (QT_CHECK_STATE)
    if (paintingActive())
        qWarning("QWidget: %s (%s) deleted while being painted", className(), name());
#endif

#ifndef QT_NO_GESTURES
    foreach (Qt::GestureType type, d->gestureContext.keys())
        ungrabGesture(type);
#endif

    // force acceptDrops false before winId is destroyed.
    d->registerDropSite(false);

#ifndef QT_NO_ACTION
    // remove all actions from this widget
    for (int i = 0; i < d->actions.size(); ++i) {
        QActionPrivate *apriv = d->actions.at(i)->d_func();
        apriv->widgets.removeAll(this);
    }
    d->actions.clear();
#endif

#ifndef QT_NO_SHORTCUT
    // Remove all shortcuts grabbed by this
    // widget, unless application is closing
    if (!QApplicationPrivate::is_app_closing && testAttribute(Qt::WA_GrabbedShortcut))
        qApp->d_func()->shortcutMap.removeShortcut(0, this, QKeySequence());
#endif

    // delete layout while we still are a valid widget
    delete d->layout;
    d->layout = 0;
    // Remove myself from focus list

    Q_ASSERT(d->focus_next->d_func()->focus_prev == this);
    Q_ASSERT(d->focus_prev->d_func()->focus_next == this);

    if (d->focus_next != this) {
        d->focus_next->d_func()->focus_prev = d->focus_prev;
        d->focus_prev->d_func()->focus_next = d->focus_next;
        d->focus_next = d->focus_prev = 0;
    }

#ifdef QT3_SUPPORT
    if (QApplicationPrivate::main_widget == this) {        // reset main widget
        QApplicationPrivate::main_widget = 0;
        QApplication::quit();
    }
#endif

    QT_TRY {
        clearFocus();
    } QT_CATCH(...) {
        // swallow this problem because we are in a destructor
    }

    d->setDirtyOpaqueRegion();

    if (isWindow() && isVisible() && internalWinId()) {
        QT_TRY {
            d->close_helper(QWidgetPrivate::CloseNoEvent);
        } QT_CATCH(...) {
            // if we're out of memory, at least hide the window.
            QT_TRY {
                hide();
            } QT_CATCH(...) {
                // and if that also doesn't work, then give up
            }
        }
    }

#if defined(Q_WS_WIN) || defined(Q_WS_X11)|| defined(Q_WS_MAC)
    else if (!internalWinId() && isVisible()) {
        qApp->d_func()->sendSyntheticEnterLeave(this);
    }
#elif defined(Q_WS_QWS) || defined(Q_WS_QPA)
    else if (isVisible()) {
        qApp->d_func()->sendSyntheticEnterLeave(this);
    }
#endif

#ifdef Q_OS_SYMBIAN
    if (d->extra && d->extra->topextra && d->extra->topextra->backingStore) {
        // Okay, we are about to destroy the top-level window that owns
        // the backing store. Make sure we delete the backing store right away
        // before the window handle is invalid. This is important because
        // the backing store will delete its window surface, which may or may
        // not have a reference to this widget that will be used later to
        // notify the window it no longer has a surface.
        d->extra->topextra->backingStore.destroy();
    }
#endif
    if (QWidgetBackingStore *bs = d->maybeBackingStore()) {
        bs->removeDirtyWidget(this);
        if (testAttribute(Qt::WA_StaticContents))
            bs->removeStaticWidget(this);
    }

    delete d->needsFlush;
    d->needsFlush = 0;

    // set all QPointers for this object to zero
    if (d->hasGuards)
        QObjectPrivate::clearGuards(this);

    if (d->declarativeData) {
        QAbstractDeclarativeData::destroyed(d->declarativeData, this);
        d->declarativeData = 0;                 // don't activate again in ~QObject
    }

#ifdef QT_MAC_USE_COCOA
    // QCocoaView holds a pointer back to this widget. Clear it now
    // to make sure it's not followed later on. The lifetime of the
    // QCocoaView might exceed the lifetime of this widget in cases
    // where Cocoa itself holds references to it.
    extern void qt_mac_clearCocoaViewQWidgetPointers(QWidget *);
    qt_mac_clearCocoaViewQWidgetPointers(this);
#endif

    if (!d->children.isEmpty())
        d->deleteChildren();

#ifndef QT_NO_ACCESSIBILITY
    QAccessible::updateAccessibility(this, 0, QAccessible::ObjectDestroyed);
#endif

    QApplication::removePostedEvents(this);

    QT_TRY {
        destroy();                                        // platform-dependent cleanup
    } QT_CATCH(...) {
        // if this fails we can't do anything about it but at least we are not allowed to throw.
    }
    --QWidgetPrivate::instanceCounter;

    if (QWidgetPrivate::allWidgets) // might have been deleted by ~QApplication
        QWidgetPrivate::allWidgets->remove(this);

    QT_TRY {
        QEvent e(QEvent::Destroy);
        QCoreApplication::sendEvent(this, &e);
    } QT_CATCH(const std::exception&) {
        // if this fails we can't do anything about it but at least we are not allowed to throw.
    }
}

Сможешь доказать, что он exception-safe?

monk ★★★★★
()
Ответ на: комментарий от monk

в виде текста нет?

є

в деструкторе этот его On_Error_на_макросах работает?

В деструкторе просто вызывается (когда не надо — не вызывается) сохранённая лямбда, а макросы просто для генерации уникальных идентификаторов и красивого синтаксиса.

utf8nowhere ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.