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


The analyzer detected a potential error that has to do with catching an exception by value. It is much better and safer to catch exceptions by reference.

Catching exceptions by value causes two types of issues. We'll discuss each of them separately.

Issue No. 1. 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 classes are declared here: an exception of a base type and an extended exception derived from the first one.

An extended exception is generated. The programmer wants to catch it, print its information, and then re-throw it.

The exception is caught by value. It means that a copy constructor will be used to create a new object, 'e', of type Exception_Base, and it will lead to 2 errors at once.

Firstly, some of the information about the exception will get lost; everything stored in Exception_Ex won't be available anymore. The virtual function Print() will only allow printing the basic information about the exception.

Secondly, what will be re-thrown is a new exception of type Exception_Base. Therefore, the information passed on will be sliced.

The fixed version of that code is as follows:

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

Now the Print() function will print all the necessary information. The "throw" statement will re-throw the already existing exception, and the information won't get lost (sliced).

Issue No. 2. Changing a temporary object.

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

The programmer wants to catch the exception, add some information to it, and re-throw it. The problem here is that it is the 's' variable that gets changed instead while the "throw;" statement re-throws the original exception. Therefore, the information about the exception won't be changed.

Correct code:

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

The pros of catching exceptions by reference are discussed in the following topics:

You can look at examples of errors detected by the V746 diagnostic.


Bugs Found

Checked Projects
346
Collected Errors
13 124