Intryguje mnie, jak działa mechanizm obsługi wyjątków w C ++. W szczególności, gdzie jest przechowywany obiekt wyjątku i jak jest on propagowany przez kilka zakresów, dopóki nie zostanie przechwycony? Czy jest przechowywany w jakimś globalnym obszarze?
Ponieważ może to być specyficzne dla kompilatora, czy ktoś mógłby to wyjaśnić w kontekście zestawu kompilatorów g ++?
c++
exception
error-handling
language-implementation
Paul Joseph
źródło
źródło
Odpowiedzi:
Implementacje mogą się różnić, ale istnieje kilka podstawowych pomysłów wynikających z wymagań.
Sam obiekt wyjątku jest obiektem utworzonym w jednej funkcji, zniszczonym w funkcji wywołującej. W związku z tym zwykle nie jest możliwe utworzenie obiektu na stosie. Z drugiej strony wiele obiektów wyjątków nie jest zbyt dużych. Ergo, można utworzyć np. 32-bajtowy bufor i przepełnić stertę, jeśli faktycznie potrzebny jest większy obiekt wyjątku.
Jeśli chodzi o faktyczne przeniesienie kontroli, istnieją dwie strategie. Jednym z nich jest zapisanie wystarczającej ilości informacji w samym stosie, aby rozwinąć stos. Jest to w zasadzie lista destruktorów do uruchomienia i programów obsługi wyjątków, które mogą przechwytywać wyjątek. Kiedy zdarzy się wyjątek, cofnij stos wykonujący te destruktory, aż znajdziesz pasujący zaczep.
Druga strategia przenosi te informacje do tabel poza stosem. Teraz, gdy wystąpi wyjątek, stos wywołań jest używany do ustalenia, które zakresy są wprowadzane, ale nie wychodzą. Są one następnie wyszukiwane w tabelach statycznych, aby określić, gdzie zostanie obsłużony zgłoszony wyjątek i które destruktory działają między nimi. Oznacza to, że na stosie jest mniej wyjątków; i tak potrzebne są adresy zwrotne. Tabele to dodatkowe dane, ale kompilator może umieścić je w segmencie programu na żądanie.
źródło
free()
lub drugiegofclose()
w jakiejś rzadko używanej ścieżce kodu.Jest to zdefiniowane w 15.1 Zgłaszanie wyjątku od standardu.
Rzut tworzy tymczasowy obiekt.
Sposób przydzielania pamięci dla tego tymczasowego obiektu nie jest określony.
Po utworzeniu tymczasowego obiektu kontrola jest przekazywana do najbliższego programu obsługi w stosie wywołań. rozwijanie stosu między punktem wyrzutu a punktem zaczepienia. Gdy stos jest rozwijany, wszystkie zmienne stosu są niszczone w odwrotnej kolejności tworzenia.
O ile wyjątek nie zostanie ponownie wyrzucony, przedmiot tymczasowy jest niszczony na końcu przewodnika, na którym został złapany.
Uwaga: Jeśli złapiesz przez odniesienie, odniesienie będzie odnosić się do tymczasowego, Jeśli złapiesz według wartości, obiekt tymczasowy jest kopiowany do wartości (i dlatego wymaga konstruktora kopiującego).
Porada S.Meyersa (Catch by const reference).
try { // do stuff } catch(MyException const& x) { } catch(std::exception const& x) { }
źródło
Możesz zajrzeć tutaj, aby uzyskać szczegółowe wyjaśnienie.
Pomocne może być również przyjrzenie się sztuczce używanej w zwykłym C, aby zaimplementować podstawowy rodzaj obsługi wyjątków. Pociąga to za sobą użycie setjmp () i longjmp () w następujący sposób: pierwsza zapisuje stos w celu oznaczenia procedury obsługi wyjątków (np. „Catch”), podczas gdy druga jest używana do „rzucania” wartości. Wartość „wyrzucona” jest widziana tak, jakby została zwrócona przez wywołaną funkcję. Blokada „try” kończy się po ponownym wywołaniu setjmp () lub po powrocie funkcji.
źródło
Wiem, że to stare pytanie, ale jest bardzo dobra ekspozycja, wyjaśniająca obie metody używane w każdym z gcc i VC tutaj: http://www.hexblog.com/wp-content/uploads/2012/06/Recon- 2012-Skochinsky-Compiler-Internals.pdf
źródło