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

В С++ существует ли разница между "throw" и "throw ex"?

Я хотел бы задать этот вопрос (также здесь), но на этот раз о С++.

В чем разница между С++ между

try { /*some code here*/}
catch(MyException& ex)
{ throw ex;} //not just throw

и

try {  /*some code here*/}
catch(MyException& ex)
{ throw;} //not throw ex

Это только в трассировке стека (который в С++ в любом случае не является стандартным, как на С# или Java)?

(Если это имеет значение, я использую MSVS 2008.)

4b9b3361

Ответ 1

throw; возвращает тот же самый объект исключения, который был обнаружен, когда throw ex; генерирует новое исключение. Это не имеет значения, кроме причин производительности для создания нового объекта исключения. Если у вас есть иерархия исключений, где есть некоторые другие классы исключений, полученные из класса MyException, и при метании исключения, которое вы сделали с помощью throw DerivedClassException;, его можно поймать с помощью catch(MyException&). Теперь, если вы измените этот пойманный объект исключения и свернете его с помощью throw;, тип объекта исключения будет DerivedClassException. Если вы выполняете throw ex;, происходит срез объекта, и вновь созданное исключение будет иметь тип MyException.

Ответ 2

[С++ FAQ Lite & sect; 17.9] Что означает throw; (без объекта исключения после ключевого слова throw)? Где я буду использовать его?

Вы можете увидеть код, который выглядит примерно так:

class MyException {
public:
  ...
  void addInfo(const std::string& info);
  ...
};

void f()
{
  try {
    ...
  }
  catch (MyException& e) {
    e.addInfo("f() failed");
    throw;
  }
}

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

Еще одна идиома повторного броска - это "диспетчер исключений":

void handleException()
{
  try {
    throw;
  }
  catch (MyException& e) {
    ...code to handle MyException...
  }
  catch (YourException& e) {
    ...code to handle YourException...
  }
}

void f()
{
  try {
    ...something that might throw...
  }
  catch (...) {
    handleException();
  }
}

Эта идиома позволяет повторить использование одной функции (handleException()) для обработки исключений в ряде других функций.

[С++ FAQ Lite & sect; 17.11] Когда я бросаю этот объект, сколько раз он будет скопирован?

Зависит. Может быть "ноль".

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

(отредактирован для большей ясности в отношении того, что, как я думал, было очевидно...)

catch(MyException& ex) { throw ex; } может копировать ex со всеми вытекающими из этого проблемами; catch(MyException& ex) { throw; } не может.

Ответ 3

Если у вас есть иерархия исключений, throw ex может разрезать ваше исключение, а throw - нет. Например:

#include <iostream> 
#include <string> 

using namespace std; 

struct base 
{ 
  virtual string who() {return "base";} 
}; 

struct derived : public base 
{ 
  string who() {return "derived";} 
}; 

int main() { 
  try { 
    try { 
      throw derived(); // throws a 'derived'
    }  
    catch (base& ex)  
    { 
      throw ex; // slices 'derived' object to be a 'base' object
    } 
  } 
  catch (base& ex) 
  { 
    cout<<ex.who()<<endl; // prints 'base'
  } 
} 

Измените throw ex на throw, и вы получите результат derived, который вы, вероятно, ожидаете получить.

Ответ 4

Вы можете использовать форму throw; с catch(...) (то есть это единственный способ перебросить, если вы поймали с помощью catch (...)).

Ответ 5

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

Ответ 6

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

Ответ 8

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