<p>All exception types that derive from boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span> can be used as type-safe containers of arbitrary data objects, while complying with the no-throw requirements (15.5.1) of the ANSI C++ standard for exception types. Data can be added to a boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span> at the time of the throw, or at a later time.</p>
<p>First, we instantiate the <spanclass="RenoLink"><ahref="error_info.html">error_info</a></span> template using a unique identifier -- tag_errno, and the type of the info it identifies -- int. This provides compile-time type safety for the various values stored in exception objects.</p>
<p>Second, we define class my_error, which derives from boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span>.</p>
<p>Finally, (3) illustrates how the typedef from (1) can be used with <spanclass="RenoLink"><ahref="exception_operator_shl.html">operator<<</a></span> to store values in exception objects at the point of the throw.</p>
<p>The <spanclass="RenoLink"><ahref="get_error_info.html">get_error_info</a></span> function template is instantiated with the typedef from (1), and is passed an exception object of a polymorphic type. If the exception object contains the requested value, the returned <spanclass="RenoLink"><ahref="http://www.boost.org/libs/smart_ptr/shared_ptr.htm">shared_ptr</a></span> will point to it; otherwise an empty <spanclass="RenoLink"><ahref="http://www.boost.org/libs/smart_ptr/shared_ptr.htm">shared_ptr</a></span> is returned.</p>
<p>Sometimes the throw site does not have all the information that is needed at the catch site to make sense of what went wrong. Let's say we have an exception type file_read_error, which takes a file name in its constructor. Consider the following function:</p>
<p>How can the file_read function pass a file name to the exception type constructor? All it has is a FILE handle.</p>
<p>Using boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span> allows us to free the file_read function from the burden of storing the file name in exceptions it throws:</p>
<p>If file_read detects a failure, it throws an exception which contains the information that is available at the time, namely the errno. Other relevant information, such as the file name, can be added in a context higher up the call stack, where it is known naturally:</p>
boost::shared_ptr<FILE> f = file_open(file_name,"rb");
assert(f);
try
{
char buf[1024];
file_read( f.get(), buf, sizeof(buf) );
}
catch(
boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span>& e )
{
e << file_name_info(file_name);
throw;
}
}</pre>
<p>The above function is (almost) exception-neutral -- if an exception is emitted by any function call within the try block, parse_file does not need to do any real work, but it intercepts any boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span> object, stores the file name, and re-throws using a throw-expression with no operand (15.1.6). The rationale for catching any boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span> object is that the file name is relevant to any failure that occurs in parse_file, <i>even if the failure is unrelated to file I/O</i>.</p>
<p>The code snippet below demonstrates how boost::<spanclass="RenoLink"><ahref="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html">tuple</a></span> can be used to bundle the name of the function that failed, together with the reported errno so that they can be added to exception objects more conveniently together:</p>
class file_open_error: public boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span> { };
boost::shared_ptr<FILE>
file_open( char const * name, char const * mode )
{
if( FILE * f=fopen(name,mode) )
return boost::shared_ptr<FILE>(f,fclose);
else
throw file_open_error() <<
file_name_info(name) <<
clib_failure("fopen",errno);
}</pre>
<p>Note that the members of a boost::<spanclass="RenoLink"><ahref="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html">tuple</a></span> are stored separately in exception objects; they can only be retrieved individually, using <spanclass="RenoLink"><ahref="get_error_info.html">get_error_info</a></span>.</p>