<html>

<head>
<meta http-equiv="Content-Language" content="en-us">
<meta name="GENERATOR" content="Microsoft FrontPage 5.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
<title>Detailed I/O Error Reporting</title>
</head>

<body>

<p>Document number: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N2655=08-0165<br>
Date:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%Y-%m-%d" startspan -->2008-06-27<!--webbot bot="Timestamp" endspan i-checksum="12418" --><br>
Project:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
Programming Language C++, Library Working Group<br>
Reply-to:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
Beman Dawes &lt;bdawes at acm.org&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<h1>Detailed Reporting for Input/Output Library Errors (Revision 1)</h1>
<p><a href="#Introduction">Introduction</a><br>
<a href="#History">Revision History</a><br>
<a href="#Motivation">Motivation</a><br>
<a href="#Approach">Approach</a><br>
<a href="#Impact-on-existing-code">Impact on existing code</a><br>
<a href="#TR2">C++0x or TR2?</a><br>
<a href="#Implementation-experience">Implementation experience</a><br>
<a href="#Sample-code">Sample code</a><br>
<a href="#Revision-history">Revision history</a><br>
<a href="#Acknowledgements">Acknowledgements</a><br>
<a href="#Proposed-wording">Proposed wording</a></p>
<h2><a name="Introduction">Introduction</a></h2>
<p>This paper proposes adding detailed error reporting, based on C++ standard 
library <i>System error support (19.4)</i>, to the C++ standard library's <i>
Input/output library (27)</i>.</p>
<h2>Revision <a name="History">History</a></h2>
<p>This is a revision of
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2629.html">
N2629</a>. The only change is moving the most recent error storage to <code>
basic_streambuf</code>&nbsp; from the derived class, eliminating the need for an 
added virtual function and simplifying the proposal.</p>
<h2><a name="Motivation">Motivation</a></h2>
<p>Lack of detailed error reporting has long been a concern about the C++ I/O 
Streams library. For example, <i>The C++ Standard Library</i> by Nicolai 
Josuttis, complained in 1999:</p>
<blockquote>
<p>Unfortunately, the standard does not require that the exception object 
includes any information about the erroneous stream or the kind of error.</p>
</blockquote>
<p>The problem is particularly acute for failures to open a file. Such failures 
are extremely common and there are numerous possible reasons for failure, such 
as the file not being found, the permissions being wrong, and so forth. 
Diagnosing these failures without knowing the exact reason for failure is 
difficult, irritating, and time wasting.</p>
<h2><a name="Approach">Approach</a></h2>
<p>The standard library now supplies support for portable reporting of 
errors from the host operating system or other low-level API's that are 
typically used to implement file based I/O streams. See 19.4 System error 
support [syserr]. Errors may be reported by either an error code or by an 
exception containing an error code. Additional categories of errors, such as 
those arising from the I/O streams themselves are also supported.</p>
<p>Failures from the current iostreams library may be reported by either setting I/O state 
bits or by throwing an exceptions. The exception thrown in such cases is <code>
ios_base::failure</code>, which is publicly derived from the standard library 
class <code>exception</code>. As iostream failures are typically a runtime problem detected by the host 
system, we would like this exception to derive from <code>std::system_error</code> 
so that a detailed error code is available.</p>
<p>Failures detected by checking I/O state bits are augmented by keeping the 
last error code  as part of the I/O state and making it available via an <code>
basic_ios::error</code> function returning a <code>const std::error_code&amp;</code>. 
Additional setter and getter functions ensure that buffers and derived classes 
can set/get the error code appropriately. Additional overloads to existing 
functions ensure backward compatibility.</p>
  <h2><a name="Impact-on-existing-code">Impact on existing code</a></h2>
  <p>Much of the proposal is an add-on, and so will have no impact on existing 
  code. In the few cases where signatures or semantics of existing functions 
  change, default behavior is carefully chosen to eliminate breakage of existing 
  code.</p>
  <p>The one known case where existing code might break is user code that 
  depends on <code>ios_base::failure</code> having specific derivation. Library 
  clause 17.4.4.7 has always granted implementors permission to derive classes 
  from classes other than the specified base, so such code is already suspect.</p>
  <p>The proposal does break ABI compatibility in that a new virtual function is 
  added and exception derivation changes.</p>
  <h2>C++0x or <a name="TR2">TR2</a>?</h2>
  <p>At the June, 2008, meeting the Library Working Group decided that the 
  proposal should be targeted toward TR2. There was insufficient time left for 
  C++0x.</p>
  <h2><a name="Implementation-experience">Implementation experience</a></h2>
  <p>A C++03 proof-of-concept prototype of the proposal has been implemented by modifying the
  <a href="http://stdcxx.apache.org/">Apache C++ Standard Library</a>. No 
  difficulties were encountered and coding was straightforward. The effort took 
  about a day and a half by someone who had no prior exposure to the 
  implementation and was designing the interface during implementation. Virtually all changes 
  were on paths through the code that are only executed when a failure has 
  already been detected.</p>
  <h2><a name="Sample-code">Sample code</a></h2>
  <blockquote>
    <pre>std::ifstream in;
in.open(&quot;no-such-file&quot;);
if (!in)
{
  std::cout &lt;&lt; in.error().message() &lt;&lt; '\n';
  return 1;
}</pre>
</blockquote>
<p>Running this as part of a program using the prototype implementation produced 
the output:</p>
<blockquote>
  <pre>No such file or directory</pre>
</blockquote>
  <h2><a name="Revision-history">Revision history</a></h2>
<p>The specification of&nbsp; <code>std::system_error</code> as a base class of
<code>std::basic_ios::failure</code> was originally proposed in
<a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2503.html">
N2503</a>, <i>Indicating iostream failures with <code>system_error</code></i>. Library 
working group (LWG) discussion at the February, 2008, Bellevue meeting sparked 
the current proposal.</p>
  <h2><a name="Acknowledgements">Acknowledgements</a></h2>
  <p>Martin Sebor suggested moving the most recent error storage to <code>
  basic_streambuf</code>&nbsp; from the derived class. Daniel Krgler identified mistakes and inconsistencies in a draft of 
  the initial version of this proposal, and suggested many useful fixes. Alisdair Meredith initiated the 
  original
  <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2503.html">
  N2503</a> proposal.</p>
  <h2><a name="Proposed-wording">Proposed wording</a></h2>
  <p><i>The proposed wording assumes 
  Library issues 805, </i>posix_error::posix_errno concerns<i>, and 832, </i>
  Applying constexpr to System error support<i>, have been accepted and applied 
  to the working paper. If either of these has not been accepted, minor changes 
  to the wording of this proposal will be required.</i></p>
  <p><i>To 27.4 Iostreams base classes [iostreams.base], Header <code>&lt;ios&gt;</code> 
  synopsis, add:</i></p>
<blockquote>
  <pre>enum class ioerrc { <span style="background-color: #C0C0C0"><i>This name goes well with errc; review if LWG 805 fails or changes errc</i></span>
  non_specific,
  stream,
  streambuf,
  rdbuf,
  exception,
  iomanip,
  filebuf,
  stringbuf,
  not_open,
  already_open,
  sentry,
  input_count,
  output_count
};

concept_map ErrorCodeEnum&lt;ioerrc&gt; {}; <i><span style="background-color: #C0C0C0">Apply if N2620 is accepted</span></i>
template &lt;&gt; struct is_error_code_enum&lt;ioerrc&gt; : public true_type {} <i><span style="background-color: #C0C0C0">Apply if N2620 is not accepted</span></i>

constexpr error_code make_error_code(ioerrc e);
constexpr error_condition make_error_condition(ioerrc e);

extern const error_category* const io_category;</pre>
</blockquote>
<p><i>In a new sub-section, Error category object, a:</i></p>
<blockquote>
  <pre>extern const error_category* const io_category;</pre>
  <blockquote>
  <p><code>
  io_category</code> shall 
  point to a statically initialized 
  object of a type derived from class <code>error_category</code>.</p>
  <p>The objects <code>default_error_condition</code> and <code>
  equivalent</code> virtual functions shall behave as specified for the class
  <code>error_category</code>. The objects <code>name</code> virtual function 
  shall return a pointer to the string <code>&quot;IO&quot;</code>. </p>
  </blockquote>
</blockquote>
  <p><i>At a location to be determined, add:</i></p>
<blockquote>
  <p><code>constexpr error_code make_error_code(ioerrc e);</code></p>
  <blockquote>
    <p><i>Returns:</i> <code>error_code(static_cast&lt;int&gt;(e), io_category)</code>.</p>
  </blockquote>
  <p><code>constexpr error_condition make_error_condition(ioerrc e);</code></p>
  <blockquote>
    <p><i>Returns:</i> <code>error_condition(static_cast&lt;int&gt;(e), io_category)</code>.</p>
  </blockquote>
</blockquote>
  <p><i>At a location to be determined, add:</i></p>
<blockquote>
  <p>Functions in this clause specified to call the <code>setstate</code> function to set 
  <code>failbit</code> or <code>badbit</code> error flags shall ensure that subsequent calls to 
  <code>error()</code> return a reference to an <code>error_code</code> object that identifies the error. The 
  <code>error_code</code> object shall either have a category of <code>io_category</code>, or be an 
  <code>error_code</code> object returned by <code>rdbuf()-&gt;puberror()</code>. </p>
</blockquote>
  <p><i>To 27.4.4.1 basic_ios constructors [basic.ios.cons], basic_ios::init() 
  effects table, add a row:</i></p>
<blockquote>
  <table border="1" cellpadding="5" cellspacing="1" style="border-collapse: collapse" bordercolor="#111111">
    <tr>
      <td><b>Element</b></td>
      <td><b>Value</b></td>
    </tr>
    <tr>
      <td><code>error()</code></td>
      <td><code>error_code()</code>if sb is not a null pointer, otherwise <code>
      error_code(ioerrc::streambuf)</code>.</td>
    </tr>
  </table>
</blockquote>
  <p><i>To 27.4.4,Class template basic_ios [ios], basic_ios synopsis, after 
  setstate(), add:</i></p>
<blockquote>
  <pre>void setstate(iostate state, const error_code&amp; ec);</pre>
</blockquote>
  <p><i>To 27.4.4,Class template basic_ios [ios], basic_ios synopsis, after 
  bad(), add:</i></p>
<blockquote>
  <pre>const error_code&amp; error() const;
void error(const error_code&amp; ec);</pre>
</blockquote>
<p><i>Change 27.4.4.3 basic_ios flags functions [iostate.flags], as indicated:</i></p>
<blockquote>
  <p><code>void setstate(iostate state);</code></p>
  <p><i>Effects:</i> Calls <font color="#FF0000"><code>
  <span style="text-decoration: line-through">clear(rdstate</span><span style="text-decoration: line-through">() 
  | state)</span></code></font> <u><code><font color="#009A9A">setstate(state, 
  error_code(ioerrc::nonspecific))</font></code></u> (which 
  may throw <code>basic_ios::failure</code> (27.4.2.1.1)).</p>
  <p><u><font color="#009A9A">[<i>Note:</i> This behavior ensures code written 
  before the addition of the two argument overload continues to work. Use of the 
  two argument overload may be preferred for new code. <i>--end note</i>]</font></u></p>
  <p><u><font color="#009A9A"><code>void setstate(iostate state, const error_code&amp; ec);</code></font></u></p>
  <blockquote>
  <p><u><font color="#009A9A"><i>Effects:</i> Calls <code>error(ec)</code>followed 
  by <code>clear(rdstate() | state)</code> (which may throw <code>
  basic_ios::failure</code> (27.4.2.1.1)).</font></u></p>
  </blockquote>
  <p><u><font color="#009A9A"><code>const error_code&amp; error() const;</code></font></u></p>
  <blockquote>
    <p><u><font color="#009A9A"><i>Returns:</i> The error code for the stream.</font></u></p>
  </blockquote>
  <p><u><font color="#009A9A"><code>void error(const error_code&amp; ec);</code></font></u></p>
  <blockquote>
    <p><u><font color="#009A9A"><i>Posconditions:</i> <code>error_code() == ec</code></font></u></p>
  </blockquote>
</blockquote>
<p><i>To 27.5.2 Class template basic_streambuf&lt;charT,traits&gt; [streambuf], 
basic_streambuf synopsis, add public functions:</i></p>
<blockquote>
  <p><code>void error(error_code&amp; ec);<br>
  const error_code&amp; error() const;</code></p>
</blockquote>
<p><i>Change 27.5.2.1 basic_streambuf constructors [streambuf.cons] as 
indicated:</i></p>
<blockquote>
<p><code>basic_streambuf();</code></p>
<blockquote>
<p><i>Effects:</i> Constructs an object of class <code>basic_streambuf&lt;charT,traits&gt;</code> 
and initializes:<br>
 all its pointer member objects to null pointers,<br>
 the <code>getloc()</code> 
member to a copy the global locale, <code>locale()</code>, at the time of construction.<br>
<font color="#009A9A"><u> the <code>error()</code> member to <code>
error_code(ioerrc::streambuf, ioerror_category)</code>.</u></font></p>
<p><i>Remarks:</i> Once the <code>getloc()</code> 
member is initialized, results of calling locale member functions, and of 
members
of facets so obtained, can safely be cached until the next time the member <code>imbue</code> 
is called.</p>
</blockquote>
<p><code>basic_streambuf(const basic_streambuf&amp; rhs);</code></p>
<blockquote>
<p><i>Effects: </i>Constructs a copy of <code>rhs</code>.</p>
<p><i>Postconditions:</i><br>
<code> eback() 
== rhs.eback()<br>
 gptr() 
== rhs.gptr()<br>
 egptr() 
== rhs.egptr()<br>
 pbase() 
== rhs.pbase()<br>
 pptr() 
== rhs.pptr()<br>
 epptr() 
== rhs.epptr()<br>
 getloc() 
== rhs.getloc()<br>
<u><font color="#009A9A"> error() 
== rhs.error()</font></u></code></p>
</blockquote>
</blockquote>
<p><i>Add a new section 27.5.2.2.6 Error reporting [streambuf.pub.error]:</i></p>
<blockquote>
  <p><code>void error(error_code&amp; ec);</code></p>
  <blockquote>
    <p><i>Effects:</i> Stores a copy of <code>ec</code>.</p>
  </blockquote>
  <p><code>const error_code&amp; error() const;</code></p>
  <blockquote>
    <p><i>Returns:</i> A reference to the stored <code>error_code</code> object.</p>
  </blockquote>
</blockquote>
<p><i>Change 27.4.2.1.1 Class ios_base::failure [ios::failure] as indicated: </i> </p>
<blockquote>
  <pre><code>
namespace std {
  class ios_base::failure : public <font color="#FF0000"><del>exception</del></font><font color="#009A9A"><ins>system_error</ins></font> {
  public:
    explicit failure(const string&amp; msg<font color="#009A9A"><ins>, const error_code&amp; ec = ioerrc::</ins><u>non_specific</u></font>);
    explicit failure(const char* msg<font color="#009A9A"><ins>, const error_code&amp; ec = ioerrc::</ins><u>non_specific</u></font>);
    virtual const char* what() const throw();
  };
}</code></pre>
  <p>The class <code>failure</code> defines the base class for the types of all objects 
  thrown as exceptions, by functions in the iostreams library, to report errors 
  detected during stream buffer operations. </p>
  <p><u><font color="#009A9A">Implementations are encouraged to report <code>
  basic_ios::error()</code> as the <code>ec</code> argument when throwing <code>ios_base::failure</code> 
  exceptions.&nbsp; [<i>Note: </i>The default value of <code>ec</code> is 
  provided to ensure code written before the addition of the second argument 
  continues to work. It is the least desirable of possible values; more specific 
  values ease error diagnosis. <i>-- end note</i>]</font></u></p>
  <p><code>explicit failure(const string&amp; msg<font color="#009A9A"><ins>, 
  const error_code&amp; ec = 
  ioerrc::</ins><u>non_specific</u></font>);</code> </p>
  <blockquote>
  <p><em>Effects:</em> Constructs an object of class <code>failure</code>. </p>
  <p><em>Postcondition:</em> <font color="#009A9A"><u> <code>code() == ec</code> and</u></font> <code>strcmp(what(), 
  msg.c_str()) == 0</code> </p>
  </blockquote>
  <p><code>explicit failure(const char* msg<font color="#009A9A"><ins>, const error_code&amp; ec = 
  ioerrc::</ins><u>non_specific</u></font>);</code> </p>
  <blockquote>
  <p><em>Effects:</em> Constructs an object of class <code>failure</code>. </p>
  <p><em>Postcondition:</em> <u><font color="#009A9A"> <code>code() == ec</code> and</font></u> <code>strcmp(what(), 
  msg ) == 0</code> </p>
  </blockquote>
</blockquote>
<hr>
  
</body>

</html>