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


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

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

4 72

4 ответа:

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

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

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

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

это определено в 15.1 бросая исключение стандарта.

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

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

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

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

совет от S. Meyers (Catch by const reference).

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

вы могли бы взглянуть здесь подробное описание.

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

Я знаю, что это старый вопрос, но есть очень хорошая экспозиция, объясняющая оба метода, используемые в каждом из gcc и VC здесь: http://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf