mirror of
https://github.com/boostorg/exception.git
synced 2025-07-04 08:16:34 +02:00
195 lines
11 KiB
HTML
195 lines
11 KiB
HTML
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'
|
|
'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'>
|
|
<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'>
|
|
<head>
|
|
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'/>
|
|
<title>transporting of arbitrary data to the catch site</title>
|
|
<link href='reno.css' type='text/css' rel='stylesheet'/>
|
|
</head>
|
|
<body>
|
|
<div class="body-0">
|
|
<div class="body-1">
|
|
<div class="body-2">
|
|
<div>
|
|
<div id="boost_logo">
|
|
<a href="http://www.boost.org"><img style="border:0" src="http://www.boost.org/boost.png" alt="Boost" width="277" height="86"/></a>
|
|
</div>
|
|
<h1>Boost Exception</h1>
|
|
</div>
|
|
<!-- Copyright (c) 2006-2008 Emil Dotchevski and Reverge Studios, Inc. -->
|
|
<!-- Distributed under the Boost Software License, Version 1.0. (See accompanying -->
|
|
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
|
|
<div class="RenoIncludeDIV"><div class="RenoAutoDIV"><h2>Transporting of Arbitrary Data to the Catch Site</h2>
|
|
</div>
|
|
<p>All exception types that derive from boost::<span class="RenoLink"><a href="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::<span class="RenoLink"><a href="exception.html">exception</a></span> at the time of the throw, or at a later time.</p>
|
|
<div class="RenoIncludeDIV"><div class="RenoAutoDIV"><h3>Adding of Arbitrary Data at the Point of the Throw</h3>
|
|
</div>
|
|
<p>The following example demonstrates how errno can be stored in exception objects using Boost Exception:</p>
|
|
<pre>#include <<span class="RenoLink"><a href="exception_hpp.html">boost/exception.hpp</a></span>>
|
|
#include <errno.h>
|
|
#include <iostream>
|
|
|
|
typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_errno,int> errno_info; //(1)
|
|
|
|
class my_error: public boost::<span class="RenoLink"><a href="exception.html">exception</a></span>, public std::exception { }; //(2)
|
|
|
|
void
|
|
f()
|
|
{
|
|
throw my_error() << errno_info(errno); //(3)
|
|
}
|
|
</pre>
|
|
<p>First, we instantiate the <span class="RenoLink"><a href="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::<span class="RenoLink"><a href="exception.html">exception</a></span>.</p>
|
|
<p>Finally, (3) illustrates how the typedef from (1) can be used with <span class="RenoLink"><a href="exception_operator_shl.html">operator<<</a></span> to store values in exception objects at the point of the throw.</p>
|
|
<p>The stored errno value can be recovered at a later time like this:</p>
|
|
<pre>// ...continued
|
|
|
|
void
|
|
g()
|
|
{
|
|
try
|
|
{
|
|
f();
|
|
}
|
|
catch(
|
|
my_error & x )
|
|
{
|
|
if( boost::shared_ptr<int const> err=boost::<span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span><errno_info>(x) )
|
|
std::cerr << "Error code: " << *err;
|
|
}
|
|
}</pre>
|
|
<p>The <span class="RenoLink"><a href="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 <span class="RenoLink"><a href="http://www.boost.org/libs/smart_ptr/shared_ptr.htm">shared_ptr</a></span> will point to it; otherwise an empty <span class="RenoLink"><a href="http://www.boost.org/libs/smart_ptr/shared_ptr.htm">shared_ptr</a></span> is returned.</p>
|
|
</div><div class="RenoIncludeDIV"><div class="RenoAutoDIV"><h3>Adding of Arbitrary Data to Active Exception Objects</h3>
|
|
</div>
|
|
<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 file_read_error which can store a file name, so that when we catch a file_read_error object, we know which file the failure is related to. However, the file_read function does not have the file name at the time of the throw; all it has is a FILE handle.</p>
|
|
<p>One possible solution is to not use FILE handles directly. We could have our own class file which stores both a FILE handle and a file name, and pass that to file_read. However, this could be problematic if we communicate with 3rd party code that does not use our class file (probably because they have their own similar class.)</p>
|
|
<p>A better solution is to make class file_read_error derive (possibly indirectly) from boost::<span class="RenoLink"><a href="exception.html">exception</a></span>, and free the file_read function from the burden of storing the file name in exceptions it throws:</p>
|
|
<pre>#include <<span class="RenoLink"><a href="exception_hpp.html">boost/exception.hpp</a></span>>
|
|
#include <stdio.h>
|
|
#include <errno.h>
|
|
|
|
typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_errno,int> errno_info;
|
|
|
|
class file_read_error: public boost::<span class="RenoLink"><a href="exception.html">exception</a></span> { };
|
|
|
|
void
|
|
file_read( FILE * f, void * buffer, size_t size )
|
|
{
|
|
if( size!=fread(buffer,1,size,f) )
|
|
throw file_read_error() << errno_info(errno);
|
|
}</pre>
|
|
<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>
|
|
<pre>#include <<span class="RenoLink"><a href="exception_hpp.html">boost/exception.hpp</a></span>>
|
|
#include <boost/shared_ptr.hpp>
|
|
#include <stdio.h>
|
|
#include <string>
|
|
|
|
typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_file_name,std::string> file_name_info;
|
|
|
|
boost::shared_ptr<FILE> file_open( char const * file_name, char const * mode );
|
|
void file_read( FILE * f, void * buffer, size_t size );
|
|
|
|
void
|
|
parse_file( char const * file_name )
|
|
{
|
|
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::<span class="RenoLink"><a href="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::<span class="RenoLink"><a href="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::<span class="RenoLink"><a href="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>As usual, the stored data can be retrieved using <span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span>.</p>
|
|
</div><div class="RenoIncludeDIV"><div class="RenoAutoDIV"><h3>Adding Grouped Data to Exceptions</h3>
|
|
</div>
|
|
<p>The code snippet below demonstrates how boost::<span class="RenoLink"><a href="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>
|
|
<pre>#include <<span class="RenoLink"><a href="exception_error_info_group_hpp.html">boost/exception/info_tuple.hpp</a></span>>
|
|
#include <boost/shared_ptr.hpp>
|
|
#include <stdio.h>
|
|
#include <string>
|
|
#include <errno.h>
|
|
|
|
typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_file_name,std::string> file_name_info;
|
|
typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_function,char const *> function_info;
|
|
typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_errno,int> errno_info;
|
|
typedef boost::tuple<function_info,errno_info> clib_failure;
|
|
|
|
class file_open_error: public boost::<span class="RenoLink"><a href="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::<span class="RenoLink"><a href="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 <span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span>.</p>
|
|
</div></div><div class="RenoAutoDIV"><div class="RenoHR"><hr/></div>
|
|
<h3>See Also:</h3>
|
|
<div class="RenoPageList"><a href="boost-exception.html">Boost Exception<br/>
|
|
</a><a href="tutorial_enable_error_info.html">Integrating Boost Exception in Existing Exception Class Hierarchies<br/>
|
|
</a></div>
|
|
</div>
|
|
<!-- Copyright (c) 2006-2008 Emil Dotchevski and Reverge Studios, Inc. -->
|
|
<!-- Distributed under the Boost Software License, Version 1.0. (See accompanying -->
|
|
<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
|
|
<div id="footer">
|
|
<p> </p>
|
|
<hr/>
|
|
<p>
|
|
<a class="logo" href="http://jigsaw.w3.org/css-validator/validator?uri=http://revergestudios.com/boost-exception/reno.css"><img class="logo_pic" src="valid-css.png" alt="Valid CSS" height="31" width="88"/></a>
|
|
<a class="logo" href="http://validator.w3.org/check?uri=referer"><img class="logo_pic" src="valid-xhtml.png" alt="Valid XHTML 1.0" height="31" width="88"/></a>
|
|
<small>Copyright (c) 2006-2008 by Emil Dotchevski and Reverge Studios, Inc.<br/>
|
|
Distributed under the <a href="http://www.boost.org/LICENSE_1_0.txt">Boost Software License, Version 1.0</a>.</small>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|