Делать заявления о выводе catch по умолчанию в С++ pass по значению или ссылке
Как оператор catch по умолчанию catch(...) {}
обнаруживает исключение по значению или по ссылке?
Во-вторых, как бросок по умолчанию throw;
генерирует исключение по значению или по ссылке?
Ответы
Ответ 1
Ловушка catch (...)
вообще не дает вам доступ к объекту исключения, поэтому вопрос является спорным. [Исправлено:] Повторное создание с помощью throw;
вызывает исходный объект. Если обработчик ухвачен по значению, то изменения в локальной копии не влияют на исходный, восстановленный объект. [/] Подробнее см. 15.3 (особенно пункт 17).
Посмотрите на некоторые из связанных вопросов справа, например этот или этот и этот и этот.
Ответ 2
Вы всегда поймаете то, что бросили.
Скажем, у вас есть класс исключений
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
}
}
Ответ 3
Бросок копирует полученное значение в определенное место реализации.
Таким образом, значение копируется при броске (это означает, что тип должен быть скопирован).
Когда вы поймаете, вы можете выбрать улов по значению или ссылке.
catch(X val) // Catch by value
{
}
catch(Y& val) // Catch by reference
{
}
Идиоматическая причина, по которой нужно уловить, состоит в том, чтобы поймать const-ссылкой. Это связано с тем, что если вы поймаете по значению, существует возможность разрезания, когда исключение копируется из его сохраненного местоположения в значение catch. Если вы поймаете по значению, значение будет уничтожено в конце блока catch. Копия в сохраненном месте уничтожается в конце блока try/catch, где она была схвачена (а не повторно брошена).
Итак, когда вы ловите catch(...)
, ничего не происходит. Исключением остается в неуказанном местоположении, что исключение уже скопировано.
Когда вы используете throw для повторного выброса исключения. throw;
. Опять ничего не происходит, поскольку исключение уже находится в неуказанном месте, и ничего не должно произойти.
Примечание: вызов throw;
, когда распространение какого-либо исключения является ошибкой, приведет к вызову std:: terminate.