W jakich okolicznościach nie będą wywoływane destruktory C++?

Wiem, że moje destruktory są wywoływane przy normalnym odwijaniu stosu i przy wyrzucaniu wyjątków, ale nie przy wywoływaniu exit ().

Czy są inne przypadki, w których moje destruktory nie zostaną wezwane? Co z sygnałami takimi jak SIGINT lub SIGSEGV? Zakładam, że dla SIGSEGV nie są one wywoływane, ale dla SIGNINT są, Skąd mam wiedzieć, które sygnały rozwiążą stos?

Czy są jakieś inne okoliczności, w których nie będą wywoływane?

Author: WilliamKF, 2010-07-05

8 answers

Czy są jakieś inne okoliczności, w których nie będą wywoływane?
  1. długie skoki: kolidują one z naturalnym procesem odwijania stosu i często prowadzą do niezdefiniowanego zachowania w C++.
  2. przedwczesne wyjścia (już je wskazałeś, choć warto zauważyć, że rzucanie już w wyniku wyrzucenia wyjątku prowadzi do nieokreślonego zachowania i dlatego nigdy nie powinniśmy wyrzucać z dtors)
  3. rzucanie z konstruktora nie wywołuje dtor dla klasy. To dlatego, jeśli przydzielasz wiele bloków pamięci zarządzanych przez kilka różnych wskaźników (a nie Inteligentne Wskaźniki) w ctor, musisz użyć bloków try na poziomie funkcji lub unikać używania listy inicjalizacyjnej i mieć blok try/catch w ciele ctor (lub jeszcze lepiej, po prostu Użyj inteligentnego wskaźnika, takiego jak scoped_ptr, ponieważ każdy członek pomyślnie zainicjowany do tej pory na liście inicjalizacyjnej zostanie zniszczony, nawet jeśli lista inicjalizacyjna zostanie usunięta. Klasa dtor nie zostanie wywołana).
  4. Jak już wspomniano, niemożność uczynienia dtor wirtualnym, gdy klasa jest usuwana przez wskaźnik bazowy, może nie wywołać podklasy dtors (undefined behavior).
  5. nie wywołanie pasującego operatora delete / delete [] dla operatora new / new[] call (undefined behavior - może nie wywołać dtor).
  6. Brak ręcznego wywołania dtor podczas używania place new z niestandardowym alokatorem pamięci w sekcji deallocate.
  7. Używanie funkcji takich jak memcpy, które kopiuje tylko jeden blok pamięci do drugiego bez wywoływania ctor. funkcje mem* są zabójcze w C++ , ponieważ buldożują nad prywatnymi danymi klasy, nadpisują Vtable itp. Rezultatem jest typowo nieokreślone zachowanie.
  8. Instancjowanie niektórych inteligentnych wskaźników (auto_ptr) na niekompletnym typie, patrz ta dyskusja
 49
Author: stinky472,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:09:57

Standard C++ nie mówi nic o tym, jak konkretne sygnały muszą być obsługiwane - wiele implementacji może nie obsługiwać SIGINT, itp. Destruktory nie będą wywoływane, jeśli wywołane zostaną exit() lub abort() lub terminate().

Edit: właśnie przeszedłem szybkie przeszukiwanie standardu C++ i nie mogę znaleźć niczego, co określałoby, jak sygnały oddziałują z żywotami obiektów - może ktoś o lepszych standardach-fu ode mnie mógłby coś znaleźć?

Dalsza edycja: podczas odpowiadania kolejne pytanie, znalazłem to w standardzie:

Przy wyjściu z zakresu (jednak dokonany), destruktory (12.4) są wywoływane dla wszystkich konstruowanych obiektów z automatycznym czasem przechowywania (3.7.2) (obiekty nazwane lub tymczasowe) które są zadeklarowane w tym zakresie, w odwrotnej kolejności ich deklaracja.

Wygląda na to, że destruktory muszą być wywołane po otrzymaniu sygnału.
 7
Author: Craig M. Brandenburg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-15 01:56:43

Innym przypadkiem, którego nie można nazwać, jest użycie polimorfizmu i nie uczynienie destruktorów bazowych wirtualnymi.

 3
Author: DanDan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-05 13:14:04

Sygnał sam w sobie nie wpłynie na wykonanie bieżącego wątku i stąd wywołanie destruktorów, ponieważ jest to inny kontekst wykonania z własnym stosem, gdzie twoje obiekty nie istnieją. To jak przerwanie: jest obsługiwane gdzieś poza kontekstem wykonania, a jeśli jest obsługiwane, kontrola jest zwracana do programu.

Podobnie jak w przypadku wielowątkowości, C++ Język nie zna pojęcia sygnałów. Te dwa są całkowicie prostopadłe do siebie i są określone przez dwa niepowiązane ze sobą standardy. Sposób ich interakcji zależy od wdrożenia, o ile nie łamie to żadnego ze standardów.

Na marginesie, innym przypadkiem jest sytuacja, gdy Destruktor obiektu nie zostanie wywołany, gdy jego konstruktor wyrzuci wyjątek. Niszczyciele członków nadal będą wywoływane.

 3
Author: Alex B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-05 23:27:13

abort wyłącza program bez wykonywania destruktorów dla obiektów o automatycznym lub statycznym czasie przechowywania, jak mówi Standard. W innych sytuacjach należy zapoznać się z dokumentami dotyczącymi wdrożenia.

 2
Author: Kirill V. Lyadvinsky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-05 12:47:24

Jeśli funkcja lub metoda ma specyfikację throws i rzuca coś, co nie jest objęte specyfikacją, domyślnym zachowaniem jest natychmiastowe wyjście. Stos nie jest rozwijany i destruktory nie są wywoływane.

Sygnały POSIX są konstrukcją specyficzną dla systemu operacyjnego i nie mają pojęcia zakresu obiektów C++. Generalnie nie można nic zrobić z sygnałem z wyjątkiem może, pułapki go, ustawić globalną zmienną flagi, a następnie obsłużyć go później w kodzie C++ Po obsługi sygnału wyjścia.

Najnowsze wersje GCC pozwalają na wyrzucenie wyjątku z synchronicznych programów obsługi sygnałów, co powoduje oczekiwany proces odwijania i niszczenia. Jest to bardzo specyficzne dla systemu operacyjnego i kompilatora, chociaż

 2
Author: karunski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-05 14:09:50

Wiele odpowiedzi tutaj, ale nadal niekompletne!

Znalazłem inny przypadek, w którym destruktory nie są wykonywane. Dzieje się tak zawsze, gdy wyjątek jest przechwytywany przez granicę biblioteki.

Zobacz więcej szczegółów tutaj:

Destruktory nie są uruchamiane (nie odwijają stosu) po wyrzuceniu wyjątku

 2
Author: Elmue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:46:49

Są zasadniczo dwie sytuacje, w których destruktory są wywoływane: na stosie unwind na końcu funkcji (lub na wyjątkach), jeśli ktoś (lub licznik referencji) wywoła delete.

Jedna szczególna sytuacja znajduje się w obiektach statycznych - są one niszczone pod koniec programu poprzez at_exit, ale jest to nadal druga sytuacja.

Który sygnał opuści at_exit może zależeć, kill -9 zabije proces natychmiast, inne sygnały powiedzą mu, aby wyszedł, ale jak dokładnie zależy od wywołania zwrotnego sygnału.

 1
Author: nob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-05 12:53:41