Как реализована среда выполнения обработки исключений С++?

Я заинтригован тем, как работает механизм обработки исключений С++. В частности, где хранится объект исключения и как он распространяется по нескольким областям, пока не будет обнаружен? Сохраняется ли она в какой-либо глобальной области?

Поскольку это может быть специфичным для компилятора, может кто-нибудь объяснить это в контексте компилятора g++?

Ответ 1

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

Сам объект исключения - это объект, созданный в одной функции, уничтоженный в его вызывающем. Следовательно, обычно невозможно создать объект в стеке. С другой стороны, многие объекты исключений не очень большие. Ergo, можно создать, например, 32-байтовый буфер и переполнение, чтобы куча, если на самом деле нужен больший объект исключения.

Что касается фактической передачи контроля, существуют две стратегии. Один из них - записать достаточную информацию в стек, чтобы развернуть стек. Это, в основном, список деструкторов для запуска и обработчиков исключений, которые могут поймать исключение. Когда происходит исключение, запустите стек, выполняющий эти деструкторы, пока не найдете соответствующий улов.

Вторая стратегия перемещает эту информацию в таблицы за пределами стека. Теперь, когда возникает исключение, стек вызовов используется для определения того, какие области ввода введены, но не выведены. Затем они просматриваются в статических таблицах, чтобы определить, где будет обрабатываться брошенное исключение, и какие деструкторы выполняются между ними. Это означает, что в стеке меньше затрат на исключение; обратные адреса необходимы в любом случае. Таблицы - это дополнительные данные, но компилятор может помещать их в сегмент программы, загруженный по требованию.

Ответ 2

Это определено в 15.1. Выбрасывание исключения из стандартного.

Бросок создает временный объект.
Как выделена память для этого временного объекта, не указывается.

После создания временного управления объектом передается ближайший обработчик в стеке вызовов. разматывание стека между точкой броска и улова. По мере удаления стека любые переменные стека уничтожаются в обратном порядке создания.

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

Примечание. Если вы поймаете по ссылке, ссылка будет ссылаться на временную. Если вы поймаете по значению, временный объект будет скопирован в значение (и, следовательно, потребуется конструктор копирования).

Совет от S.Meyers(ссылка Catch by const).

try
{
    // do stuff
}
catch(MyException const& x)
{
}
catch(std::exception const& x)
{
}

Ответ 3

Вы можете посмотреть здесь для подробного объяснения.

Это может также помочь взглянуть на трюк, используемый в простой C, чтобы реализовать некоторую базовую обработку исключений. Это подразумевает использование setjmp() и longjmp() следующим образом: первый сохраняет стек, чтобы отметить обработчик исключений (например, "catch" ), в то время как последний используется для "выброса" значения. "Заброшенное" значение отображается так, как если бы оно было возвращено из вызываемой функции. "Try block" заканчивается, когда setjmp() вызывается снова или когда функция возвращается.