「More C++ Idioms/多態的例外(Polymorphic Exception)」の版間の差分

削除された内容 追加された内容
76 行
 
The ''throw'' statement has been moved into virtual functions. The ''raise'' function invoked in function ''foo'' is polymorphic and selects the implementation in either ''ExceptionBase'' or ''ExceptionDerived'' class depending upon what is passed as a parameter (dependency injection). Type of ''*this'' is obviously known at compile-time, which results into raising a polymorphic exception. The structure of this idiom is very similar to that of [[More C++ Idioms/Virtual Constructor|Virtual Constructor]] idiom.
 
'''Propagating a polymorphic exception'''
 
Quite often an exception is handled in multiple catch statements to treat it differently in different layers of the program/library. In such cases, the earlier catch blocks need to rethrow the exception so that the outer catch blocks, if any, may take the necessary actions. When a polymorphic exception is involved, inner catch block(s) may modify the exception object before passing it on to the catch blocks up in the stack. In such cases, care must be taken to ensure that the original exception object is propagated. Consider a seemingly annocuous looking program below, which fails to do that.
 
<source lang="cpp">
try {
foo(e); // throws an instance of ExceptionDerived as before.
}
catch (ExceptionBase& e) // Note the base class. Exception is caught polymorphically.
{
// Handle the exception. May modify the original exception object.
throw e; // Warning! Object slicing is underway.
}
</source>
 
The ''throw e'' statement does not throw the original exception object. Instead, it throws a sliced copy (only ExceptionBase part) of the original object because it considers the static type of the expression in front of it. Silently, the derived exception object was not only lost but also translated into the base type exception object. The catch blocks up in the stack do not have access to the same information this catch had. There are two ways to address the problem.
 
* Simply use ''throw;'' (without any expression following it). It will rethrow the original exception object.
* Use polymorphic exception idiom again. It will throw a copy of the original exception object because the ''raise()'' virtual function uses ''*this''.
 
<source lang="cpp">
try {
foo(e); // throws an instance of ExceptionDerived as before.
}
catch (ExceptionBase& e) // Note the base class. Exception is caught polymorphically.
{
// Handle the exception. May modify the original exception object.
// Use only one of the following two.
throw; // Option 1: Original derived exception is thrown.
e.raise(); // Option 2: A copy of the original derived exception object is thrown.
}
</source>
 
=== Known Uses ===