Catch исключение указателем в С++

Я обнаружил, что есть три способа поймать исключение, каковы различия?

1) поймать по значению;

2) ловить по ссылке;

3) уловить указатель;

Я знаю только, что catch по значению вызовет две копии объекта, catch по ссылке вызовет один. Итак, как насчет улова по указателю? Когда использовать улов по указателю? В дополнение к бросанию объекта, могу ли я указать указатель на такой объект?

class A {}

void f() {

  A *p = new A();
        throw p;


}

Ответ 1

Рекомендуемый способ - бросить по значению и уловить по ссылке.

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

Если вы действительно чувствуете, что должны бросать указатель, используйте умный указатель, например shared_ptr.

В любом случае, Херб Саттер и Алексей Александреску объясняют это очень хорошо в своей книге стандартов кодирования С++, которую я перефразировал.

См. Стандарты кодирования С++: выброс по значению, поиск по ссылке.

Ответ 2

Catch следует правилам совместимости с обычным назначением, то есть, если вы выбрали значение, вы можете поймать его как значение или ссылку, но не как указатель; если вы бросаете указатель, вы можете поймать его только как указатель (или ссылку на указатель...).

Но на самом деле не имеет смысла бросать указатели, это приведет только к головным болям управления памятью. Таким образом, вы должны, в общем, следовать правилу throw by value, catch by reference, как объяснил Грегори.

Ответ 3

Microsoft MFC использует catch by pointer, но я думаю, что это было для совместимости с компилятором, прежде чем попытка и улов были правильно реализованы; первоначально они использовали макросы TRY и CATCH для имитации. Каждое исключение происходит от CException, у которого есть способ определить, должен ли объект быть удален.

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

Ответ 4

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

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

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

Ответ 5

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

Однако некоторые библиотеки (Boost.Graph делает это, я считаю) используют throw для передачи возвращаемого значения обратно вызывающему из функции с глубокой рекурсией; в такой ситуации возвращаемое значение может быть указателем, поэтому бросание указателя имеет смысл.