1<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN' 2'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'> 3<html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'> 4<head> 5 <meta http-equiv='Content-Type' content='text/html; charset=utf-8'/> 6 <title>Motivation</title> 7 <link href='reno.css' type='text/css' rel='stylesheet'/> 8</head> 9<body> 10<div class="body-0"> 11<div class="body-1"> 12<div class="body-2"> 13<div> 14<div id="boost_logo"> 15<a href="http://www.boost.org"><img style="border:0" src="../../../boost.png" alt="Boost" width="277" height="86"/></a> 16</div> 17<h1>Boost Exception</h1> 18</div> 19<!-- Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. --> 20<!-- Distributed under the Boost Software License, Version 1.0. (See accompanying --> 21<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> 22<div class="RenoIncludeDIV"><div class="RenoAutoDIV"><h3>Motivation</h3> 23</div> 24<p>Traditionally, when using exceptions to report failures, the throw site:</p> 25<div><ul><li>creates an exception object of the appropriate type, and</li> 26<li>stuffs it with data relevant to the detected error.</li> 27</ul></div> 28<p>A higher context in the program contains a catch statement which:</p> 29<div><ul><li>selects failures based on exception types, and</li> 30<li>inspects exception objects for data required to deal with the problem.</li> 31</ul></div> 32<p>The main issue with this "traditional" approach is that often, the data available at the point of the throw is insufficient for the catch site to handle the failure.</p> 33<p>Here is an example of a catch statement:</p> 34<pre>catch( file_read_error & e ) 35 { 36 std::cerr << e.file_name(); 37 }</pre> 38<p>And here is a possible matching throw:</p> 39<pre>void 40read_file( FILE * f ) 41 { 42 .... 43 size_t nr=fread(buf,1,count,f); 44 if( ferror(f) ) 45 throw file_read_error(???); 46 .... 47 }</pre> 48<p>Clearly, the problem is that the handler requires a file name but the read_file function does not have a file name to put in the exception object; all it has is a FILE pointer!</p> 49<p>In an attempt to deal with this problem, we could modify read_file to accept a file name:</p> 50<pre>void 51read_file( FILE * f, char const * name ) 52 { 53 .... 54 size_t nr=fread(buf,1,count,f); 55 if( ferror(f) ) 56 throw file_read_error(name); 57 .... 58 }</pre> 59<p>This is not a real solution: it simply shifts the burden of supplying a file name to the immediate caller of the read_file function.</p> 60<blockquote><p><i>In general, the data required to handle a given library-emitted exception depends on the program that links to it. Many contexts between the throw and the catch may have relevant information which must be transported to the exception handler.</i></p></blockquote> 61<h3>Exception wrapping</h3> 62<p>The idea of exception wrapping is to catch an exception from a lower level function (such as the read_file function above), and throw a new exception object that contains the original exception (and also carries a file name.) This method seems to be particularly popular with C++ programmers with Java background.</p> 63<p>Exception wrapping leads to the following problems:</p> 64<div><ul><li>To wrap an exception object it must be copied, which may result in slicing.</li> 65<li>Wrapping is practically impossible to use in generic contexts.</li> 66</ul></div> 67<p>The second point is actually special case of violating the exception neutrality principle. Most contexts in a program can not handle exceptions; such contexts should not interfere with the process of exception handling.</p> 68<h3>The boost::exception solution</h3> 69<div><ul><li>Simply derive your exception types from boost::<span class="RenoLink"><a href="exception.html">exception</a></span>.</li> 70<li>Confidently limit the throw site to provide only data that is available naturally.</li> 71<li>Use exception-neutral contexts between the throw and the catch to augment exceptions with more relevant data as they bubble up.</li> 72</ul></div> 73<p>For example, in the throw statement below we only add the errno code, since this is the only failure-relevant information available in this context:</p> 74<pre>struct exception_base: virtual std::exception, virtual boost::<span class="RenoLink"><a href="exception.html">exception</a></span> { }; 75struct io_error: virtual exception_base { }; 76struct file_read_error: virtual io_error { }; 77 78typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_errno_code,int> errno_code; 79 80void 81read_file( FILE * f ) 82 { 83 .... 84 size_t nr=fread(buf,1,count,f); 85 if( ferror(f) ) 86 throw file_read_error() <span class="RenoLink"><a href="exception_operator_shl.html"><<</a></span> errno_code(errno); 87 .... 88 }</pre> 89<p>In a higher exception-neutral context, we add the file name to <i>any</i> exception that derives from boost::<span class="RenoLink"><a href="exception.html">exception</a></span>:</p> 90<pre>typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_file_name,std::string> file_name; 91 92.... 93try 94 { 95 if( FILE * fp=fopen("foo.txt","rt") ) 96 { 97 shared_ptr<FILE> f(fp,fclose); 98 .... 99 read_file(fp); //throws types deriving from boost::<span class="RenoLink"><a href="exception.html">exception</a></span> 100 do_something(); 101 .... 102 } 103 else 104 throw file_open_error() <span class="RenoLink"><a href="exception_operator_shl.html"><<</a></span> errno_code(errno); 105 } 106catch( boost::<span class="RenoLink"><a href="exception.html">exception</a></span> & e ) 107 { 108 e <span class="RenoLink"><a href="exception_operator_shl.html"><<</a></span> file_name("foo.txt"); 109 throw; 110 }</pre> 111<p>Finally here is how the handler retrieves data from exceptions that derive from boost::<span class="RenoLink"><a href="exception.html">exception</a></span>:</p> 112<pre>catch( io_error & e ) 113 { 114 std::cerr << "I/O Error!\n"; 115 116 if( std::string const * fn=<span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span><file_name>(e) ) 117 std::cerr << "File name: " << *fn << "\n"; 118 119 if( int const * c=<span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span><errno_code>(e) ) 120 std::cerr << "OS says: " << strerror(*c) << "\n"; 121 }</pre> 122<p>In addition, boost::<span class="RenoLink"><a href="diagnostic_information.html">diagnostic_information</a></span> can be used to compose an automatic (if not user-friendly) message that contains all of the <span class="RenoLink"><a href="error_info.html">error_info</a></span> objects added to a boost::<span class="RenoLink"><a href="exception.html">exception</a></span>. This is useful for inclusion in logs and other diagnostic objects.</p> 123</div><div class="RenoAutoDIV"><div class="RenoHR"><hr/></div> 124See also: <span class="RenoPageList"><a href="boost-exception.html">Boost Exception</a> | <a href="exception_types_as_simple_semantic_tags.html">Exception Types as Simple Semantic Tags</a> | <a href="frequently_asked_questions.html">Frequently Asked Questions</a> | <a href="tutorial_enable_error_info.html">Integrating Boost Exception in Existing Exception Class Hierarchies</a></span> 125</div> 126<!-- Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. --> 127<!-- Distributed under the Boost Software License, Version 1.0. (See accompanying --> 128<!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) --> 129<div id="footer"> 130<p> 131<a class="logo" href="http://jigsaw.w3.org/css-validator/check/referer"><img class="logo_pic" src="valid-css.png" alt="Valid CSS" height="31" width="88"/></a> 132<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> 133<small>Copyright (c) 2006-2009 by Emil Dotchevski and Reverge Studios, Inc.<br/> 134Distributed under the <a href="http://www.boost.org/LICENSE_1_0.txt">Boost Software License, Version 1.0</a>.</small> 135</p> 136</div> 137</div> 138</div> 139</div> 140</body> 141</html> 142