Подтвердить что ты не робот

Потеря исключений при реорганизации исключения из блока catch

Сегодня я обнаружил ошибку в блоке catch:

catch (const exception& e){
    // do something
    // throw e; <-- bug!
    throw;    // <-- right thing to do
}

В принципе, если я явно выражу исключение e, я получаю новый std::exception реконструированный, на самом деле сообщение из метода what() было по умолчанию std::string вместо моего настраиваемого сообщения.

Какое объяснение? Я думал, что throw; является только сокращением throw ExceptionJustCaught;.

4b9b3361

Ответ 1

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

Если вы скажете throw e;, время жизни исходного исключения заканчивается в конце блока catch, и вы выбрасываете новое исключение, копируя e, создавая таким образом классическую нарезку Проблема: поскольку e является полиморфной ссылкой на объект, динамический тип которого обычно более выражен, чем std::exception, вы в конечном итоге срезаете производную часть объекта.

В отличие от этого, throw; - это специальный оператор, который реактивирует исходное исключение, так что он больше не захватывается, а его время жизни больше не заканчивается в конце блока. Фактически, если вы поймаете непостоянную ссылку, вы можете продолжать модифицировать объект исключения и реконструировать и, таким образом, связывать изменение состояния с нижними блоками catch. Но имейте в виду, что повторное открытие отличается от нового исключения!

Ответ 2

Просто throw выдает текущее исключение по ссылке. throw e copy создает новое исключение для броска. Это почти то же самое, что работает return.