Анализатор обнаружил потенциальную ошибку, связанную с перехватом исключения по значению. Намного лучше и безопасней перехватывать исключение по ссылке.
Вообще, перехват исключения по значению порождает две разновидности ошибок. Рассмотрим их поочередно.
Проблема 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; }
Подробнее про преимущества перехвата исключения по ссылке можно прочитать здесь:
Данная диагностика классифицируется как:
|
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V746. |