V746. Object slicing. An exception should be caught by reference rather than by value.
Анализатор обнаружил потенциальную ошибку, связанную с перехватом исключения по значению. Намного лучше и безопасней перехватывать исключение по ссылке.
Вообще, перехват исключения по значению порождает две разновидности ошибок. Рассмотрим их поочередно.
Проблема N1. Срезка (slicing).
class Exception_Base {
....
virtual void Print() { .... }
};
class Exception_Ex : public Exception_Base { .... };
try
{
if (error) throw Exception_Ex(1, 2, 3);
}
catch (Exception_Base e)
{
e.Print();
throw e;
}
Объявлено 2 класса: исключение базового типа и расширенное исключение, которое наследуется от первого.
Генерируется расширенное исключение. Это исключение планируется перехватить, распечатать о нём информацию и пробросить исключение дальше.
Исключение перехвачено по значению. Это значит, что с помощью конструктора копирования будет сконструирован новый объект 'e' типа Exception_Base. Это порождает сразу 2 ошибки.
Во-первых, часть информации об исключении потеряна. Всё что хранилось Exception_Ex нам более недоступно. Виртуальная функция Print() позволит вывести базовую информацию о проблеме.
Во-вторых, дальше будет проброшено уже новое исключение типа Exception_Base. Таким образом мы передали дальше урезанную информацию о возникшей проблеме.
Правильно будет использовать следующий код:
catch (Exception_Base &e)
{
e.Print();
throw;
}
Теперь функция Print() распечатает всю нужную информацию. Оператор "throw" будет пробрасывать далее уже существующее исключение, и информация не будет потеряна (срезана).
Проблема N2. Изменение временного объекта.
catch (std::string s)
{
s += "Additional info";
throw;
}
Программист хочет перехватить исключение, добавить какую-то дополнительную информацию и пробросить это исключение дальше. Ошибка в том, что изменяется переменная 's', а оператор "throw;" пробрасывает далее исходное исключение. Таким образом мы не изменили информацию о исключении.
Правильный вариант:
catch (std::string &s)
{
s += "Additional info";
throw;
}
Подробнее про преимущества перехвата исключения по ссылке можно прочитать здесь:
- Stack Overflow. C++ catch blocks - catch exception by value or reference?
- Stack Overflow. Catch exception by pointer in C++.
- Стефан К. Дьюхэрст. Скользкие места С++. Как избежать проблем при проектировании и компиляции ваших программ. – М.: ДМК Пресс. – 264 с.: ил. ISBN 5-94074-083-9.
- Wikipedia. Object slicing.
Данная диагностика классифицируется как:
|
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V746. |