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?
8 answers
Czy są jakieś inne okoliczności, w których nie będą wywoływane?
- długie skoki: kolidują one z naturalnym procesem odwijania stosu i często prowadzą do niezdefiniowanego zachowania w C++.
- 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)
- 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).
- 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).
- nie wywołanie pasującego operatora delete / delete [] dla operatora new / new[] call (undefined behavior - może nie wywołać dtor).
- Brak ręcznego wywołania dtor podczas używania place new z niestandardowym alokatorem pamięci w sekcji deallocate.
- 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.
- Instancjowanie niektórych inteligentnych wskaźników (auto_ptr) na niekompletnym typie, patrz ta dyskusja
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:
Wygląda na to, że destruktory muszą być wywołane po otrzymaniu sygnału.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.
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.
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.
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.
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ż
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
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.
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