diff --git a/doc/adding_data_at_throw.html b/doc/adding_data_at_throw.html deleted file mode 100644 index 7e4af8a..0000000 --- a/doc/adding_data_at_throw.html +++ /dev/null @@ -1,73 +0,0 @@ - - -
- -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().
-When you catch a boost::exception, you can call clone_exception() to get an exception_ptr object:
-#include <boost/exception/cloning.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( - boost::exception & e ) - { - error = boost::clone_exception(e); - } - }-
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:
-// ...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 clone_exception() and rethrow_exception() in the above examples is well-formed.
-The code snippet below demonstrates how boost::tuple 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:
-#include <boost/exception/info_tuple.hpp> -#include <boost/shared_ptr.hpp> -#include <stdio.h> -#include <string> -#include <errno> - -typedef boost::error_info<struct tag_file_name,std::string> file_name_info; -typedef boost::error_info<struct tag_function,char const *> function_info; -typedef boost::error_info<struct tag_errno,int> errno_info; -typedef boost::tuple<function_info,errno_info> clib_failure; - -class file_open_error: public boost::exception { }; - -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); - }-
Note that the members of a boost::tuple are stored separately in exception objects; they can only be retrieved individually, using get_error_info().
-Here is how cloning can be enabled in a throw-expression (15.1):
-#include <boost/exception/enable_exception_cloning.hpp> -#include <boost/exception/info.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 boost::enable_exception_cloning(file_read_error()) << - errno_info(errno); - }-