<divclass="RenoIncludeDIV"><h2>Transporting of Arbitrary Data to the Catch Site</h2>
<p>All exception types that derive from <tt>boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span></tt> 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 classes. Data can be added to a <tt>boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span></tt> at the time of the throw, or at a later time.</p>
<divclass="RenoIncludeDIV"><h3>Adding of Arbitrary Data at the Point of the Throw</h3>
<p>The following example demonstrates how <tt>errno</tt> can be stored in exception objects using Boost Exception:</p>
<p>First, we instantiate the <tt><spanclass="RenoLink"><ahref="error_info.html">error_info</a></span></tt> template using a unique identifier -- <tt>tag_errno</tt>, and the type of the info it identifies -- <tt>int</tt>. This provides compile-time type safety for the various values stored in exception objects.</p>
<p>Second, we define class <tt>my_error</tt>, which derives from <tt>boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span></tt>.</p>
<p>Finally, (3) illustrates how the <tt>typedef</tt> from (1) can be used with <tt><spanclass="RenoLink"><ahref="operator_shl_exception.html">operator<<</a></span>()</tt> to store values in exception objects at the point of the throw.</p>
<p>The stored <tt>errno</tt> value can be recovered at a later time like this:</p>
<p>The <tt><spanclass="RenoLink"><ahref="get_error_info.html">get_error_info</a></span>()</tt> function template is instantiated with the <tt>typedef</tt> from (1), and is passed an exception object of any type that derives publicly from <tt>boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span></tt>. If the exception object contains the requested value, the returned <tt><spanclass="RenoLink"><ahref="http://www.boost.org/libs/smart_ptr/shared_ptr.htm">shared_ptr</a></span></tt> will point to it; otherwise an empty <tt><spanclass="RenoLink"><ahref="http://www.boost.org/libs/smart_ptr/shared_ptr.htm">shared_ptr</a></span></tt> is returned.</p>
</div><divclass="RenoIncludeDIV"><h3>Adding of Arbitrary Data to Active Exception Objects</h3>
<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. Here is an example:</p>
<pre>#include <stdio.h>
#include <string>
class
file_read_error
{
public:
explicit
file_read_error( std::string const & fn ):
fn_(fn)
{
};
std::string const &
file_name() const
{
return fn_;
}
private:
std::string fn_;
};
void
file_read( FILE * f, void * buffer, size_t size )
{
if( size!=fread(buffer,1,size,f) )
throw file_read_error("????");
}</pre>
<p>We have defined an exception class <tt>file_read_error</tt> which can store a file name, so that when we catch a <tt>file_read_error</tt> object, we know which file the failure is related to. However, the <tt>file_read</tt> function does not have the file name at the time of the throw; all it has is a <tt>FILE</tt> handle.</p>
<p>One possible solution is to not use <tt>FILE</tt> handles directly. We could have our own <tt>class file</tt> which stores both a <tt>FILE</tt> handle and a file name, and pass that to <tt>file_read()</tt>. However, this could be problematic if we communicate with 3rd party code that does not use our <tt>class file</tt> (probably because they have their own similar class.)</p>
<p>A better solution is to make class <tt>file_read_error</tt> derive (possibly indirectly) from <tt>boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span></tt>, and free the <tt>file_read()</tt> function from the burden of storing the file name in exceptions it throws:</p>
<p>If <tt>file_read()</tt> detects a failure, it throws an exception which contains the information that is available at the time, namely the <tt>errno</tt>. 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 <tt>try</tt> block, <tt>parse_file()</tt> does not need to do any real work, but it intercepts any <tt>boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span></tt> object, stores the file name, and re-throws using a throw-expression with no operand (15.1.6). The rationale for catching any <tt>boost::<spanclass="RenoLink"><ahref="exception.html">exception</a></span></tt> object is that the file name is relevant to any failure that occurs in <tt>parse_file()</tt>, <i>even if the failure is unrelated to file I/O</i>.</p>
<p>As usual, the stored data can be retrieved using <tt><spanclass="RenoLink"><ahref="get_error_info.html">get_error_info</a></span>()</tt>.</p>
</div><divclass="RenoIncludeDIV"><h3>Adding Grouped Data to Exceptions</h3>
<p>The code snippet below demonstrates how <tt>boost::<spanclass="RenoLink"><ahref="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html">tuple</a></span></tt> can be used to bundle the name of the function that failed, together with the reported <tt>errno</tt> 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 <tt>boost::<spanclass="RenoLink"><ahref="http://www.boost.org/libs/tuple/doc/tuple_users_guide.html">tuple</a></span></tt> are stored separately in exception objects; they can only be retrieved individually, using <tt><spanclass="RenoLink"><ahref="get_error_info.html">get_error_info</a></span>()</tt>.</p>