Rozumiem, że gdy coś jest throw
n, stos jest `` rozwijany '' do punktu, w którym jest przechwytywany, a destruktory instancji klas na stosie w każdym kontekście funkcji są uruchamiane (dlatego nie należy rzucać wyjątku z destruktora - mógłbyś skończyć rzuceniem drugiego) ... ale zastanawiam się, gdzie w pamięci jest przechowywany obiekt, który rzuciłem, gdy to się dzieje?
Czy jest to zależne od implementacji? Jeśli tak, to czy jest jakaś konkretna metoda używana przez najpopularniejsze kompilatory?
c++
exception
exception-handling
sje397
źródło
źródło
raise
), zniszcz go. Problem z alokacją sterty polega na tym, co zrobić, jeśli próba przydzielenia wyjątku nie powiedzie się? Musiałbyś przerwać (tak jak w przypadku przepełnienia stosu, jeśli umieszczenie go na stosie „nie powiedzie się” z powodu braku miejsca). W przeciwieństwie do Java implementacja nie może zamiast tego zgłosić innego wyjątku.Odpowiedzi:
Tak, odpowiedź zależy od kompilatora.
Szybki eksperyment z moim kompilatorem (
g++ 4.4.3
) ujawnia, że jego bibliotekamalloc
uruchomieniowa najpierw próbuje zapamiętać wyjątek i, w przypadku niepowodzenia, próbuje przydzielić miejsce w „buforze awaryjnym” obejmującym cały proces, który żyje w segmencie danych. Jeśli to nie zadziała, dzwonistd::terminate()
.Wydawałoby się, że głównym celem bufora awaryjnego jest możliwość wyrzucenia
std::bad_alloc
po tym, jak procesowi zabraknie miejsca na stercie (w takim przypadkumalloc
wywołanie zakończy się niepowodzeniem).Odpowiednią funkcją jest
__cxa_allocate_exception
:extern "C" void * __cxxabiv1::__cxa_allocate_exception(std::size_t thrown_size) throw() { void *ret; thrown_size += sizeof (__cxa_refcounted_exception); ret = malloc (thrown_size); if (! ret) { __gnu_cxx::__scoped_lock sentry(emergency_mutex); bitmask_type used = emergency_used; unsigned int which = 0; if (thrown_size > EMERGENCY_OBJ_SIZE) goto failed; while (used & 1) { used >>= 1; if (++which >= EMERGENCY_OBJ_COUNT) goto failed; } emergency_used |= (bitmask_type)1 << which; ret = &emergency_buffer[which][0]; failed:; if (!ret) std::terminate (); } // We have an uncaught exception as soon as we allocate memory. This // yields uncaught_exception() true during the copy-constructor that // initializes the exception object. See Issue 475. __cxa_eh_globals *globals = __cxa_get_globals (); globals->uncaughtExceptions += 1; memset (ret, 0, sizeof (__cxa_refcounted_exception)); return (void *)((char *)ret + sizeof (__cxa_refcounted_exception)); }
Nie wiem, jak typowy jest ten schemat.
źródło
malloc
połączenie zakończy się niepowodzeniem”, zwykle, ale niekoniecznie.Z tej strony :
Teraz to tylko Itanium ABI i szukam szczegółów specyficznych dla GCC, Clang i MSVC. Jednak standard niczego nie określa i wydaje się, że jest to oczywisty sposób implementacji przechowywania wyjątków, więc ...
źródło
Nie wiem, czy to odpowie na twoje pytanie, ale ten (Jak kompilator C ++ implementuje obsługę wyjątków) jest w ogóle doskonałym artykułem o obsłudze wyjątków:. Gorąco polecam (:
Przepraszam za krótką odpowiedź, ale cała informacja w artykule jest świetna, nie mogę tutaj wybrać i opublikować niektórych informacji.
źródło
excpt_info
tej stronie, daje trochę informacji, jak robi to MSVC.Standard C ++ ogólnie określa, jak zachowuje się język, ale nie określa, jak kompilator powinien zaimplementować to zachowanie. Myślę, że to pytanie należy do tej kategorii. Najlepszy sposób na zaimplementowanie czegoś takiego zależy od specyfiki maszyny - niektóre procesory mają wiele rejestrów ogólnego przeznaczenia, inne mają ich niewiele. Procesor może być nawet zbudowany ze specjalnym rejestrem tylko dla wyjątków, w którym to przypadku kompilator powinien mieć swobodę korzystania z tej funkcji.
źródło
Cóż, nie może być na stosie, ponieważ zostanie rozwinięty i nie może znajdować się na stercie, ponieważ oznaczałoby to, że system prawdopodobnie nie mógł rzucić
std::bad_alloc
. Poza tym wszystko zależy od implementacji: nie określono implementacji (co musi być udokumentowane), ale nie określono. (Implementacja może używać sterty przez większość czasu, o ile ma jakąś awaryjną kopię zapasową, która pozwoli na ograniczoną liczbę wyjątków, nawet jeśli nie ma już pamięci).źródło
std::bad_alloc
działania. Oznacza to, że implementacja nie może systematycznie używać sterty. Norma na to nie pozwala. Opieram swoje roszczenia na standardzie.