Исключение catch исключений С++

Возможный дубликат:
Область объекта исключения в С++

У меня есть следующие уловки catch:

catch(Widget w);
catch(Widget& w);

void passAndThrowWidget() {
          Widget localWidget;
      throw localWidget;
}

Если мы поймаем объект Widget по значению, компилятор сделает копию, поэтому, когда мы бросаем исключение, localWidget выходит за пределы области видимости, и мы не видим никаких проблем.

Если мы поймаем объект byget byget, в соответствии с эталонной концепцией, "w" указывает на тот же локальный виджет, а не на копию. Но я видел, что большинство исключений попадают в ссылки на С++. Мой вопрос о том, как это работает как "localWidget", выходит за пределы области, когда генерируется исключение и улавливается ссылочными точками на уничтоженный объект.

Спасибо!

Ответ 1

throw expr; похож на return expr; тем, что использует инициализацию копирования (инициализация списка также возможна с С++ 0x). Но это (главным образом) синтаксис.

Когда дело доходит до семантики, то точно так же, как возвращающее значение из функции, возвращающей не ссылочный тип, отлично, так что бросает:

T f()
{
    // t is local but this is clearly fine
    T t;
    return t;

    // and so is this
    throw t;
}

Кроме того, не указано, является ли то, что возвращается или выбрано, является результатом выражения оператора return или throw или копии (или перемещения) из этого выражения.

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

Ответ 2

Среда выполнения С++ использует ячейку памяти, не зависящую от стека, для хранения объектов исключений:

2.4.2 Выделение объекта исключения

Хранение необходимо для исключений выброшены. Это хранилище должно сохраняться в то время как стек разматывается, так как он будет использоваться обработчиком и быть потокобезопасным. Объект исключения поэтому хранение обычно будет выделено в кучу, хотя реализации могут обеспечить аварийный буфер для поддержки метания bad_alloc исключения при низкой памяти условия (см. Раздел 3.3.1).

(из С++ ABI для Itanium: Обработка исключений)

Таким образом, ссылка, которую вы получаете, когда вы "поймаете по ссылке", является ссылкой на эту ячейку памяти, а не ссылкой на освобожденный стек стека. Это означает, что объекты исключений гарантированно живут достаточно долго, чтобы их обработчики исключений использовали даже в том случае, если они были получены путем ссылки. (Вероятно, они будут освобождены после того, как вы выйдете из области catch, однако, не держитесь за ссылки на исключения.)

Ответ 3

Исключения - это исключение из правила локальной области видимости:

try
{
    Widget w;
    throw w;
}
catch (const Widget& exc)
{
    // exc is a valid reference to the Widget
}

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

Ответ 4

В этой строке вы создаете копию своего локального объекта,

throw localWidget;

Итак, он не ссылается на ваш локальный объект "localWidget", кроме копии этого объекта (называемого объектом исключения), который, как гарантируется, будет жить до тех пор, пока исключение не будет полностью обработано предложением catch.

Ответ 5

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

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