Как оператор catch по умолчанию catch(...) {}
обнаруживает исключение по значению или по ссылке?
Во-вторых, как бросок по умолчанию throw;
генерирует исключение по значению или по ссылке?
Как оператор catch по умолчанию catch(...) {}
обнаруживает исключение по значению или по ссылке?
Во-вторых, как бросок по умолчанию throw;
генерирует исключение по значению или по ссылке?
Ловушка catch (...)
вообще не дает вам доступ к объекту исключения, поэтому вопрос является спорным. [Исправлено:] Повторное создание с помощью throw;
вызывает исходный объект. Если обработчик ухвачен по значению, то изменения в локальной копии не влияют на исходный, восстановленный объект. [/] Подробнее см. 15.3 (особенно пункт 17).
Посмотрите на некоторые из связанных вопросов справа, например этот или этот и этот и этот.
Вы всегда поймаете то, что бросили. Скажем, у вас есть класс исключений
class MyException { public: int m_data; MyException(int data) { printf("MyException::MyException() ctor\n"); m_data = data; } MyException(const MyException & other) { printf("MyException::MyException() copy ctor\n"); } ~MyException() { printf("MyException::~MyException() dtor\n"); } };
1) Если вы указали указатель, вы получите указатель:
Пример 1:
void f() { throw new MyException() } void main() { try{ f(); } catch(MyException * ex) // You WILL catch the pointer { delete ex; // You should delete the exception object } catch(MyException & ex) // You WILL NOT catch the pointer { } }
Пример 2:
void main() { try{ f(); } catch(...) // You WILL catch the pointer, but will be unable to access it { throw; // You are rethrowing the pointer } }
2) Если вы бросили объект, вы поймаете ссылку на него:
Пример 1:
void f() { printf("f BEGIN\n"); throw MyException(1); // MyException ctor is called printf("f END\n"); } void main() { printf("main BEGIN\n"); try { f(); } catch(MyException & ex) // You WILL catch a reference to created object { printf("catch MyException: %d\n", ex.m_data); } // MyException dtor is called here!! printf("main END\n"); }
Производится следующий вывод:
main BEGIN
f BEGIN
MyException::MyException() ctor
catch MyException: 1
MyException::~MyException() dtor
main END
Пример 2:
void main() { try { f(); } catch(...) // You WILL catch a reference to created object, //but will be unable to access it { throw; // You throw the reference } }
Бросок копирует полученное значение в определенное место реализации.
Таким образом, значение копируется при броске (это означает, что тип должен быть скопирован).
Когда вы поймаете, вы можете выбрать улов по значению или ссылке.
catch(X val) // Catch by value
{
}
catch(Y& val) // Catch by reference
{
}
Идиоматическая причина, по которой нужно уловить, состоит в том, чтобы поймать const-ссылкой. Это связано с тем, что если вы поймаете по значению, существует возможность разрезания, когда исключение копируется из его сохраненного местоположения в значение catch. Если вы поймаете по значению, значение будет уничтожено в конце блока catch. Копия в сохраненном месте уничтожается в конце блока try/catch, где она была схвачена (а не повторно брошена).
Итак, когда вы ловите catch(...)
, ничего не происходит. Исключением остается в неуказанном местоположении, что исключение уже скопировано.
Когда вы используете throw для повторного выброса исключения. throw;
. Опять ничего не происходит, поскольку исключение уже находится в неуказанном месте, и ничего не должно произойти.
Примечание: вызов throw;
, когда распространение какого-либо исключения является ошибкой, приведет к вызову std:: terminate.