motivation.html 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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 &amp; e )
  35. {
  36. std::cerr &lt;&lt; e.file_name();
  37. }</pre>
  38. <p>And here is a possible matching throw:</p>
  39. <pre>void
  40. read_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
  51. read_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> { };
  75. struct io_error: virtual exception_base { };
  76. struct file_read_error: virtual io_error { };
  77. typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span>&lt;struct tag_errno_code,int&gt; errno_code;
  78. void
  79. read_file( FILE * f )
  80. {
  81. ....
  82. size_t nr=fread(buf,1,count,f);
  83. if( ferror(f) )
  84. throw file_read_error() <span class="RenoLink"><a href="exception_operator_shl.html">&lt;&lt;</a></span> errno_code(errno);
  85. ....
  86. }</pre>
  87. <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>
  88. <pre>typedef boost::<span class="RenoLink"><a href="error_info.html">error_info</a></span>&lt;struct tag_file_name,std::string&gt; file_name;
  89. ....
  90. try
  91. {
  92. if( FILE * fp=fopen("foo.txt","rt") )
  93. {
  94. shared_ptr&lt;FILE&gt; f(fp,fclose);
  95. ....
  96. read_file(fp); //throws types deriving from boost::<span class="RenoLink"><a href="exception.html">exception</a></span>
  97. do_something();
  98. ....
  99. }
  100. else
  101. throw file_open_error() <span class="RenoLink"><a href="exception_operator_shl.html">&lt;&lt;</a></span> errno_code(errno);
  102. }
  103. catch( boost::<span class="RenoLink"><a href="exception.html">exception</a></span> &amp; e )
  104. {
  105. e <span class="RenoLink"><a href="exception_operator_shl.html">&lt;&lt;</a></span> file_name("foo.txt");
  106. throw;
  107. }</pre>
  108. <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>
  109. <pre>catch( io_error &amp; e )
  110. {
  111. std::cerr &lt;&lt; "I/O Error!\n";
  112. if( std::string const * fn=<span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span>&lt;file_name&gt;(e) )
  113. std::cerr &lt;&lt; "File name: " &lt;&lt; *fn &lt;&lt; "\n";
  114. if( int const * c=<span class="RenoLink"><a href="get_error_info.html">get_error_info</a></span>&lt;errno_code&gt;(e) )
  115. std::cerr &lt;&lt; "OS says: " &lt;&lt; strerror(*c) &lt;&lt; "\n";
  116. }</pre>
  117. <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>
  118. </div><div class="RenoAutoDIV"><div class="RenoHR"><hr/></div>
  119. See also: <span class="RenoPageList"><a href="boost-exception.html">Boost Exception</a>&nbsp;| <a href="exception_types_as_simple_semantic_tags.html">Exception Types as Simple Semantic Tags</a>&nbsp;| <a href="frequently_asked_questions.html">Frequently Asked Questions</a>&nbsp;| <a href="tutorial_enable_error_info.html">Integrating Boost Exception in Existing Exception Class Hierarchies</a></span>
  120. </div>
  121. <!-- Copyright (c) 2006-2009 Emil Dotchevski and Reverge Studios, Inc. -->
  122. <!-- Distributed under the Boost Software License, Version 1.0. (See accompanying -->
  123. <!-- file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -->
  124. <div id="footer">
  125. <p>
  126. <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>
  127. <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>
  128. <small>Copyright (c) 2006-2009 by Emil Dotchevski and Reverge Studios, Inc.<br/>
  129. Distributed under the <a href="http://www.boost.org/LICENSE_1_0.txt">Boost Software License, Version 1.0</a>.</small>
  130. </p>
  131. </div>
  132. </div>
  133. </div>
  134. </div>
  135. </body>
  136. </html>