Catching std:: exception по ссылке?
У меня есть глупый вопрос. Я прочитал эту статью о std:: exception http://www.cplusplus.com/doc/tutorial/exceptions/
В catch (exception& e)
он говорит:
Мы поместили обработчик, который ловит объекты исключений по ссылке (обратите внимание на амперсанд и после типа), поэтому он также ловит классы, производные от исключения, например наш myex-объект класса myexception.
Означает ли это, что, используя "&" вы также можете перехватить исключение родительского класса? Я думал и предопределен в std:: exception, потому что лучше передать e (std:: exception) в качестве ссылки, чем объект.
Ответы
Ответ 1
Причиной использования &
с исключениями является не столько полиморфизм, сколько исключение slicing. Если бы вы не использовали &
, С++ попытался бы скопировать брошенное исключение во вновь созданный std::exception
, потенциально потеряв информацию в этом процессе. Пример:
#include <stdexcept>
#include <iostream>
class my_exception : public std::exception {
virtual const char *what() const throw() {
return "Hello, world!";
}
};
int main() {
try {
throw my_exception();
} catch (std::exception e) {
std::cout << e.what() << std::endl;
}
return 0;
}
Это будет печатать сообщение по умолчанию для std::exception
(в моем случае, St9exception
), а не Hello, world!
, потому что исходный объект исключения был потерян путем нарезки. Если мы изменим это на &
:
#include <stdexcept>
#include <iostream>
class my_exception : public std::exception {
virtual const char *what() const throw() {
return "Hello, world!";
}
};
int main() {
try {
throw my_exception();
} catch (std::exception &e) {
std::cout << e.what() << std::endl;
}
return 0;
}
Теперь мы видим Hello, world!
.
Ответ 2
Означает ли это, что, используя "&" вы также можете поймать исключение родительского класса?
Нет, это не увеличивает объем использования исключений (например, из родительского класса класса, содержащего код try/catch).
Он также не увеличивает типы исключений, которые могут быть пойманы, по сравнению с ловом по значению (catch(std::exception e)
без &
), вы все равно поймаете каждое исключение, которое либо равно std::exception
, либо происходит от него).
То, что он увеличивает, - это количество данных, которое вы действительно получите, когда поймаете исключение.
Если возникает исключение, которое происходит от std::exception
, и вы его поймаете по значению, то вы выбрасываете какое-либо дополнительное поведение в этом классе исключений. Он разбивает polymorphism на класс исключения, из-за Slicing.
Пример:
class MyException : public std::exception
{
public:
virtual const char* what() const
{
return "hello, from my exception!";
}
};
// ...
try
{
throw MyException();
}
catch(std::exception& e)
{
// This will print "hello, from my exception!"
std::cout << e.what() << "\n";
}
// ...
try
{
throw MyException();
}
catch(std::exception e)
{
// This will print "Unknown exception"
std::cout << e.what() << "\n";
}
Ответ 3
Нет &
не имеет никакого отношения к полиморфному характеру обработчиков исключений. Их формулировка очень плохая, она, похоже, указывает, что &
как-то ответственна. Это не тот случай. Вы правы, &
просто передает по ссылке, которая немного эффективнее.
Также, как правило, вы действительно должны стараться избегать cplusplus.com.
Обновленная ссылка: Что не так с cplusplus.com
Ответ 4
Использование ссылки на исключение здесь может уменьшить создаваемые временные объекты, а также сохранить полиморфизм.