Меня заинтриговало, как работает механизм обработки исключений C ++. В частности, где хранится объект исключения и как он распространяется через несколько областей, пока не будет обнаружен? Он хранится в какой-то глобальной области?
Поскольку это может быть специфическим для компилятора, может ли кто-нибудь объяснить это в контексте пакета компиляторов g ++?
Ответы:
Реализации могут отличаться, но есть несколько основных идей, которые вытекают из требований.
Сам объект исключения - это объект, созданный в одной функции, уничтоженный в ее вызывающей стороне. Следовательно, обычно невозможно создать объект в стеке. С другой стороны, многие объекты исключений не очень большие. Следовательно, можно создать, например, 32-байтовый буфер и переполнить его в кучу, если действительно нужен более крупный объект исключения.
Что касается фактической передачи контроля, существует две стратегии. Один из них - записать достаточно информации в сам стек, чтобы раскрутить стек. По сути, это список деструкторов для запуска и обработчиков исключений, которые могут перехватить исключение. Когда происходит исключение, запустите стек, выполняя эти деструкторы, пока не найдете подходящий улов.
Вторая стратегия перемещает эту информацию в таблицы вне стека. Теперь, когда возникает исключение, стек вызовов используется, чтобы узнать, в какие области входят, но не выходят. Затем они просматриваются в статических таблицах, чтобы определить, где будет обрабатываться выброшенное исключение и какие деструкторы будут выполняться между ними. Это означает, что в стеке меньше накладных расходов на исключение; Обратные адреса все равно нужны. Таблицы представляют собой дополнительные данные, но компилятор может поместить их в загружаемый по запросу сегмент программы.
источник
free()
или символаfclose()
в некоторых редко используемых путях кода.Это определено в 15.1. Создание исключения из стандарта.
Бросок создает временный объект.
Как выделяется память для этого временного объекта, не определено.
После создания временного объекта управление передается ближайшему обработчику в стеке вызовов. раскручивание стека между точкой выброса и точкой захвата. При раскручивании стека все переменные стека уничтожаются в обратном порядке создания.
Если исключение не генерируется повторно, временное состояние уничтожается в конце обработчика, в котором оно было обнаружено.
Примечание. Если вы перехватываете по ссылке, ссылка будет относиться к временному. Если вы перехватываете по значению, временный объект копируется в значение (и, следовательно, требует конструктора копирования).
Совет от С.Мейерса (ловить по постоянной ссылке).
try { // do stuff } catch(MyException const& x) { } catch(std::exception const& x) { }
источник
Вы можете посмотреть здесь подробное объяснение.
Также может быть полезно взглянуть на трюк, используемый в простом C для реализации некоторого базового вида обработки исключений. Это влечет за собой использование setjmp () и longjmp () следующим образом: первый сохраняет стек, чтобы отметить обработчик исключений (например, «catch»), а второй используется для «выброса» значения. «Выброшенное» значение выглядит так, как если бы оно было возвращено вызываемой функцией. «Блок попытки» заканчивается, когда снова вызывается setjmp () или когда функция возвращается.
источник
Я знаю, что это старый вопрос, но здесь есть очень хорошее изложение, объясняющее оба метода, используемые в каждом из gcc и VC: http://www.hexblog.com/wp-content/uploads/2012/06/Recon- 2012-Скочинский-Compiler-Internals.pdf
источник