diff --git a/doc/adding_data_at_throw.html b/doc/adding_data_at_throw.html new file mode 100644 index 0000000..7e4af8a --- /dev/null +++ b/doc/adding_data_at_throw.html @@ -0,0 +1,73 @@ + + +
+ +The following example demonstrates how errno can be stored in exception objects using Boost Exception:
+#include <boost/exception.hpp> +#include <errno.h> +#include <iostream> + +typedef boost::error_info<struct tag_errno,int> errno_info; //(1) + +class my_error: public boost::exception, public std::exception { }; //(2) + +void +f() + { + throw my_error() << errno_info(errno); //(3) + } ++
First, we instantiate the error_info 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.
+Second, we define class my_error, which derives from boost::exception.
+Finally, (3) illustrates how the typedef from (1) can be used with operator<<() to store values in exception objects at the point of the throw.
+The stored errno value can be recovered at a later time like this:
+// ...continued
+
+void
+g()
+ {
+ try
+ {
+ f();
+ }
+ catch(
+ my_error & x )
+ {
+ if( boost::shared_ptr<int const> err=boost::get_error_info<errno_info>(x) )
+ std::cerr << "Error code: " << *err;
+ }
+ }
+The get_error_info() function template is instantiated with the typedef from (1), and is passed an exception object of any type that derives publicly from boost::exception. If the exception object contains the requested value, the returned shared_ptr will point to it; otherwise an empty shared_ptr is returned.
+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:
+#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("????"); + }+
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.
+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.)
+A better solution is to make class file_read_error derive (possibly indirectly) from boost::exception, and free the file_read() function from the burden of storing the file name in exceptions it throws:
+#include <boost/exception.hpp> +#include <stdio.h> +#include <errno.h> + +typedef boost::error_info<struct tag_errno,int> errno_info; + +class file_read_error: public boost::exception { }; + +void +file_read( FILE * f, void * buffer, size_t size ) + { + if( size!=fread(buffer,1,size,f) ) + throw file_read_error() << errno_info(errno); + }+
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:
+#include <boost/exception.hpp> +#include <boost/shared_ptr.hpp> +#include <stdio.h> +#include <string> + +typedef boost::error_info<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::exception & e ) + { + e << file_name_info(file_name); + throw; + } + }+
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::exception object, stores the file name, and re-throws using a throw-expression with no operand (15.1.6). The rationale for catching any boost::exception object is that the file name is relevant to any failure that occurs in parse_file(), even if the failure is unrelated to file I/O.
+As usual, the stored data can be retrieved using get_error_info().
+The ability to add data to exception objects after they have been passed to throw is important, because often some of the information needed to handle an exception is unavailable in the context where the failure is detected.
Boost Exception also supports cloning of exception objects, implemented non-intrusively and automatically by the boost::throw_exception() function.
Boost Exception was accepted as a Boost library on November 7, 2007; however it has not yet been part of an official Boost release.
+Boost Exception was accepted as a Boost library on November 7 2007, however it has not yet been part of an official Boost release. Current version can be downloaded from Boost SVN.
#include <boost/exception.hpp>
@@ -128,10 +128,11 @@ boost typedef ---unspecified--- exception_ptr; template <class T> - ---unspecified--- enable_exception_cloning( T const & e ); + ---unspecified--- enable_current_exception( T const & e ); + exception_ptr current_exception(); template <class T> - exception_ptr clone_exception( T const & e ); + exception_ptr copy_exception( T const & e ); void rethrow_exception( exception_ptr const & ep ); class @@ -299,22 +300,24 @@ boostThis macro is designed to be used with operator<<() when throwing a boost::exception, to store information about the location of the throw statement. It can be chained with other error_infos in a single throw expression.
#include <boost/exception/cloning.hpp>
+#include <boost/exception_ptr.hpp>
namespace
boost
{
typedef ---unspecified--- exception_ptr;
}
-The exception_ptr type can be used to refer to a copy of a boost::exception object. It is Default Constructible, Copy Constructible, Assignable and Equality Comparable; exception_ptr's operations do not throw.
+The exception_ptr type can be used to refer to a copy of an exception object. It is Default Constructible, Copy Constructible, Assignable and Equality Comparable; exception_ptr's operations do not throw.
Two instances of exception_ptr are equivalent and compare equal if and only if they refer to the same exception.
The default constructor of exception_ptr produces the null value of the type. The null value is equivalent only to itself.
-#include <boost/exception/enable_exception_cloning.hpp>
+exception_ptr objects are returned by current_exception() and copy_exception().
+#include <boost/exception/enable_current_exception.hpp>
namespace boost { template <class T> - ---unspecified--- enable_exception_cloning( T const & e ); + ---unspecified--- enable_current_exception( T const & e ); }
T must have an accessible no-throw copy constructor
@@ -329,29 +332,39 @@ my_exception: }; .... -throw boost::enable_exception_cloning(my_exception()); -Unless enable_exception_cloning() is called at the time an exception object is used in a throw-expression, any attempt to copy it using clone_exception() returns an exception_ptr which refers to an instance of unknown_exception.
+throw boost::enable_current_exception(my_exception()); +Unless enable_current_exception() is called at the time an exception object is used in a throw-expression, any attempt to copy it using current_exception() returns an exception_ptr which refers to an instance of unknown_exception.
Instead of using the throw keyword directly, it is preferable to call boost::throw_exception(). This is guaranteed to throw an exception that derives from boost::exception and supports cloning.
-#include <boost/exception/cloning.hpp>
+#include <boost/exception_ptr.hpp>
+namespace
+boost
+ {
+ exception_ptr current_exception();
+ }
+The current_exception() function must not be called outside of a catch block.
+#include <boost/exception_ptr.hpp>
namespace boost { template <class T> - exception_ptr clone_exception( T const & e ); + exception_ptr copy_exception( T const & e ); }-
T must be polymorphic.
-It is unspecified whether the return values of two successive calls to clone_exception() refer to the same exception object.
+As if try { throw e; } catch( ... ) { return current_exception(); }
#include <boost/exception/cloning.hpp>
+#include <boost/exception_ptr.hpp>
namespace boost { @@ -362,7 +375,7 @@ boostThrows:
The exception to which ep refers.
#include <boost/exception/cloning.hpp>
+#include <boost/exception_ptr.hpp>
namespace boost { @@ -374,8 +387,7 @@ boost ---unspecified--- }; }-
This type is used by the cloning support in Boost Exception.
-To allow an exception to be cloned, enable_exception_cloning() must be used at the time the exception object is passed to throw. Otherwise, calling clone_exception() returns an exception_ptr which refers to an instance of unknown_exception.
+This type is used by the cloning support in Boost Exception. Please see current_exception().
#include <boost/throw_exception.hpp>
@@ -390,7 +402,7 @@ boost #endif }Boost Exception supports transporting of exception objects between threads through cloning. This system is similar to N2179, but because Boost Exception can not rely on language support, the use of enable_exception_cloning() at the time of the throw is required in order to use cloning.
+Boost Exception supports transporting of exception objects between threads through cloning. This system is similar to N2179, but because Boost Exception can not rely on language support, the use of enable_current_exception() at the time of the throw is required in order to use cloning.
All exceptions emitted by the familiar function boost::throw_exception() are guaranteed to derive from boost::exception and to support cloning.
-Here is how cloning can be enabled in a throw-expression (15.1):
-#include <boost/exception/enable_exception_cloning.hpp> +#include <boost/exception/enable_current_exception.hpp> #include <boost/exception/info.hpp> #include <stdio.h> #include <errno.h> @@ -35,12 +35,12 @@ void file_read( FILE * f, void * buffer, size_t size ) { if( size!=fread(buffer,1,size,f) ) - throw boost::enable_exception_cloning(file_read_error()) << + throw boost::enable_current_exception(file_read_error()) << errno_info(errno); }
When you catch a boost::exception, you can call clone_exception() to get an exception_ptr object:
-#include <boost/exception/cloning.hpp> +When you catch a boost::exception, you can call current_exception() to get an exception_ptr object:
+#include <boost/exception_ptr.hpp> #include <boost/thread.hpp> #include <boost/bind.hpp> @@ -55,12 +55,12 @@ worker_thread( boost::except error = boost::exception_ptr(); } catch( - boost::exception & e ) + ... ) { - error = boost::clone_exception(e); + error = boost::current_exception(); } }-In the above example, note that clone_exception() captures the original type of the exception object, even though e refers to the base type boost::exception. This original type can be thrown again using the rethrow_exception() function:
+In the above example, note that current_exception() captures the original type of the exception object, even though e refers to the base type boost::exception. This original type can be thrown again using the rethrow_exception() function:
// ...continued void @@ -72,11 +72,11 @@ work() if( error ) boost::rethrow_exception(error); }
-Clone_exception() could fail to copy the original exception object in the following cases:
+Clone_exception() could fail to copy the original exception object in the following cases:
-
- if there is not enough memory, in which case the returned exception_ptr points to an instance of std::bad_alloc, or
-- if enable_exception_cloning() was not used in the throw-expression passed to the original throw statement, in which case the returned exception_ptr points to an instance of unknown_exception.
+- if enable_current_exception() was not used in the throw-expression passed to the original throw statement, in which case the returned exception_ptr points to an instance of unknown_exception.
Regardless, the use of clone_exception() and rethrow_exception() in the above examples is well-formed.
+Regardless, the use of current_exception() and rethrow_exception() in the above examples is well-formed.
When you catch a boost::exception, you can call current_exception() to get an exception_ptr object:
+#include <boost/exception_ptr.hpp> +#include <boost/thread.hpp> +#include <boost/bind.hpp> + +void do_work(); //throws cloning-enabled boost::exceptions + +void +worker_thread( boost::exception_ptr & error ) + { + try + { + do_work(); + error = boost::exception_ptr(); + } + catch( + ... ) + { + error = boost::current_exception(); + } + }+
In the above example, note that current_exception() captures the original type of the exception object, even though e refers to the base type boost::exception. This original type can be thrown again using the rethrow_exception() function:
+// ...continued + +void +work() + { + boost::exception_ptr error; + boost::thread t( boost::bind(worker_thread,boost::ref(error)) ); + t.join(); + if( error ) + boost::rethrow_exception(error); + }+
Clone_exception() could fail to copy the original exception object in the following cases:
+Regardless, the use of current_exception() and rethrow_exception() in the above examples is well-formed.
+#include <boost/exception_ptr.hpp>
+namespace
+boost
+ {
+ template <class T>
+ exception_ptr copy_exception( T const & e );
+ }
+As if try { throw e; } catch( ... ) { return current_exception(); }
+#include <boost/exception_ptr.hpp>
+namespace
+boost
+ {
+ exception_ptr current_exception();
+ }
+The current_exception() function must not be called outside of a catch block.
+#include <boost/exception/enable_current_exception.hpp>
+namespace
+boost
+ {
+ template <class T>
+ ---unspecified--- enable_current_exception( T const & e );
+ }
+T must have an accessible no-throw copy constructor
+An object of unspecified type which derives publicly from T. That is, the returned object can be intercepted by a catch(T &).
+This function is designed to be used directly in a throw-expression to enable the cloning support in Boost Exception. For example:
+class
+my_exception:
+ public std::exception
+ {
+ };
+
+....
+throw boost::enable_current_exception(my_exception());
+Unless enable_current_exception() is called at the time an exception object is used in a throw-expression, any attempt to copy it using current_exception() returns an exception_ptr which refers to an instance of unknown_exception.
+Instead of using the throw keyword directly, it is preferable to call boost::throw_exception(). This is guaranteed to throw an exception that derives from boost::exception and supports cloning.
+This header file contains the following definitions/declarations:
-This header file contains the following definitions/declarations:
-