﻿# V746\. Object slicing\. An exception should be caught by reference rather than by value\.

Анализатор обнаружил потенциальную ошибку, связанную с перехватом исключения по значению\. Намного лучше и безопасней перехватывать исключение по ссылке\.

Вообще, перехват исключения по значению порождает две разновидности ошибок\. Рассмотрим их поочередно\.

**Проблема N1\. Срезка \(slicing\)\.**

```cpp
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\. Таким образом мы передали дальше урезанную информацию о возникшей проблеме\.

Правильно будет использовать следующий код:

```cpp
catch (Exception_Base &e)
{
  e.Print();
  throw;
}
```

Теперь функция Print\(\) распечатает всю нужную информацию\. Оператор "throw" будет пробрасывать далее уже существующее исключение, и информация не будет потеряна \(срезана\)\.

**Проблема N2\. Изменение временного объекта\.**

```cpp
catch (std::string s)
{
  s += "Additional info";
  throw;
}
```

Программист хочет перехватить исключение, добавить какую\-то дополнительную информацию и пробросить это исключение дальше\. Ошибка в том, что изменяется переменная 's', а оператор "throw;" пробрасывает далее исходное исключение\. Таким образом мы не изменили информацию о исключении\.

Правильный вариант:

```cpp
catch (std::string &s)
{
  s += "Additional info";
  throw;
}
```

Подробнее про преимущества перехвата исключения по ссылке можно прочитать здесь: 

1. Stack Overflow\. [C\+\+ catch blocks \- catch exception by value or reference?](https://stackoverflow.com/questions/2522299/c-catch-blocks-catch-exception-by-value-or-reference)
1. Stack Overflow\. [Catch exception by pointer in C\+\+](https://stackoverflow.com/questions/2023032/catch-exception-by-pointer-in-c)\.
1. Стефан К\. Дьюхэрст\. Скользкие места С\+\+\. Как избежать проблем при проектировании и компиляции ваших программ\. – М\.: ДМК Пресс\. – 264 с\.: ил\. ISBN 5\-94074\-083\-9\.
1. Wikipedia\. [Object slicing](https://en.wikipedia.org/wiki/Object_slicing)\.