motivation.html
8.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<!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>Motivation</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="../../../boost.png" alt="Boost" width="277" height="86"/></a>
</div>
<h1>Boost Exception</h1>
</div>
<!-- Copyright (c) 2006-2009 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"><h3>Motivation</h3>
</div>
<p>Traditionally, when using exceptions to report failures, the throw site:</p>
<div><ul><li>creates an exception object of the appropriate type, and</li>
<li>stuffs it with data relevant to the detected error.</li>
</ul></div>
<p>A higher context in the program contains a catch statement which:</p>
<div><ul><li>selects failures based on exception types, and</li>
<li>inspects exception objects for data required to deal with the problem.</li>
</ul></div>
<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>
<p>Here is an example of a catch statement:</p>
<pre>catch( file_read_error & e )
{
std::cerr << e.file_name();
}</pre>
<p>And here is a possible matching throw:</p>
<pre>void
read_file( FILE * f )
{
....
size_t nr=fread(buf,1,count,f);
if( ferror(f) )
throw file_read_error(???);
....
}</pre>
<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>
<p>In an attempt to deal with this problem, we could modify read_file to accept a file name:</p>
<pre>void
read_file( FILE * f, char const * name )
{
....
size_t nr=fread(buf,1,count,f);
if( ferror(f) )
throw file_read_error(name);
....
}</pre>
<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>
<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>
<h3>Exception wrapping</h3>
<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>
<p>Exception wrapping leads to the following problems:</p>
<div><ul><li>To wrap an exception object it must be copied, which may result in slicing.</li>
<li>Wrapping is practically impossible to use in generic contexts.</li>
</ul></div>
<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>
<h3>The boost::exception solution</h3>
<div><ul><li>Simply derive your exception types from boost::<span class="RenoLink"><a href="exception.html">exception</a></span>.</li>
<li>Confidently limit the throw site to provide only data that is available naturally.</li>
<li>Use exception-neutral contexts between the throw and the catch to augment exceptions with more relevant data as they bubble up.</li>
</ul></div>
<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>
<pre>struct exception_base: virtual std::exception, virtual boost::<span class="RenoLink"><a href="exception.html">exception</a></span> { };
struct io_error: virtual exception_base { };
struct file_read_error: virtual io_error { };
typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_errno_code,int> errno_code;
void
read_file( FILE * f )
{
....
size_t nr=fread(buf,1,count,f);
if( ferror(f) )
throw file_read_error() <span class="RenoLink"><a href="exception_operator_shl.html"><<</a></span> errno_code(errno);
....
}</pre>
<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>
<pre>typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span><struct tag_file_name,std::string> file_name;
....
try
{
if( FILE * fp=fopen("foo.txt","rt") )
{
shared_ptr<FILE> f(fp,fclose);
....
read_file(fp); //throws types deriving from boost::<span class="RenoLink"><a href="exception.html">exception</a></span>
do_something();
....
}
else
throw file_open_error() <span class="RenoLink"><a href="exception_operator_shl.html"><<</a></span> errno_code(errno);
}
catch( boost::<span class="RenoLink"><a href="exception.html">exception</a></span> & e )
{
e <span class="RenoLink"><a href="exception_operator_shl.html"><<</a></span> file_name("foo.txt");
throw;
}</pre>
<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>
<pre>catch( io_error & e )
{
std::cerr << "I/O Error!\n";
if( std::string const * fn=<span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span><file_name>(e) )
std::cerr << "File name: " << *fn << "\n";
if( int const * c=<span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span><errno_code>(e) )
std::cerr << "OS says: " << strerror(*c) << "\n";
}</pre>
<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>
</div><div class="RenoAutoDIV"><div class="RenoHR"><hr/></div>
See 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>
</div>
<!-- Copyright (c) 2006-2009 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>
<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>
<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-2009 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>