Rewrite the boost::throws() reference documentation. Add tests of boost::throws() using the divide() function from the reference documentation. Having tests will allow us to change the implementation of throws() without fear of silently breaking it.

This commit is contained in:
Beman
2017-09-07 15:00:26 -04:00
parent c493242855
commit 1bb5b95ebd
2 changed files with 85 additions and 35 deletions

View File

@ -60,8 +60,7 @@
&nbsp;&nbsp;&nbsp;<a href="#Class-error_condition-constructors">Class <code>error_condition</code> constructors</a><br>
&nbsp;&nbsp;&nbsp;<a href="#Class-error_condition-modifiers">Class <code>error_condition</code> modifiers</a><br>
&nbsp;&nbsp;&nbsp;<a href="#Class-error_condition-observers">Class <code>error_condition</code> observers</a><br>
<a href="#throws-object"><code>throws</code> object</a><br>
<a href="#Semantics-of-throws">Semantics of <code>throws</code> object</a><br>
<a href="#Function-boost-throws">Function <code>boost::throws()</code></a><br>
<a href="#Non-member-functions">Non-member functions</a><br>
<a href="#Header-system_error">Header &lt;boost/system/system_error.hpp&gt;</a><br>
&nbsp;&nbsp;&nbsp;<a href="#Class-system_error">Class <code>system_error</code></a><br>
@ -316,8 +315,12 @@ fixed by globally adding () to these names to turn them into function calls.</p>
operator&lt;&lt;( basic_ostream&lt;charT,traits&gt;&amp; os, const error_code &amp; ec );
size_t hash_value( const error_code &amp; ec );
}
}</pre>
} // namespace system
system::error_code &amp; throws();
} // namespace boost</pre>
</blockquote>
<p>The value of each<code> errc_t</code> constant shall be the same as the
value of the <code>&lt;cerrno&gt;</code> macro shown in the above synopsis.</p>
@ -644,36 +647,6 @@ observers</a></h3>
<code>int</code>) that can occur with <code>bool</code> are not allowed,
eliminating some sources of user error. One possible implementation choice for
this type is pointer to member. <i>--end note</i> <i>]</i></p>
</blockquote>
<h2><a name="throws-object"><code>throws</code> object</a></h2>
<pre>extern error_code throws;</pre>
<p>The predefined <code>error_code</code> object <code>throws</code> is supplied
for use as a &quot;throw on error&quot; tag.</p>
<h2><a name="Semantics-of-throws">Semantics of <code>throws</code></a> object</h2>
<p>Functions that specify an argument in the form <code>error_code&amp; ec=throws</code>,
with appropriate namespace qualifiers, have the following error handling
semantics:</p>
<blockquote>
<p><i>Postconditions:</i></p>
<blockquote>
<p>If <code>&amp;ec != &amp;throws</code> and an error occurred:</p>
<ul>
<li> <code>ec.value()</code> returns the implementation specific error
number for the particular error that occurred.</li>
<li><code>ec.category()</code> returns the <code>
<a href="#Class-error_category">error_category</a></code> for <code>ec.value()</code>.</li>
</ul>
<p>if <code>&amp;ec != &amp;throws</code> and an error did not occur, <code>ec.clear()</code>.</p>
</blockquote>
<p><i>Throws:</i></p>
<blockquote>
<p>If an error occurs and <code>&amp;ec == &amp;throws</code>, throws an exception of type
<code><a href="#Class-system_error">system_error</a></code> or of a type
derived from <code><a href="#Class-system_error">system_error</a></code>. The
exception's <code>code()</code> member function returns a reference to an
<code>error_code</code> object with the behavior specified in <i>
Postconditions</i>.</p>
</blockquote>
</blockquote>
<h2><a name="Non-member-functions">Non-member functions</a></h2>
<pre>bool operator==( const error_code &amp; lhs, const error_code &amp; rhs ) noexcept;</pre>
@ -736,6 +709,37 @@ bool operator!=( const error_condition &amp; condition, const error_code &amp; c
<p><i>Returns: </i>&nbsp;A hash value representing <code>ec</code>.</p>
</blockquote>
<h2><a name="Function-boost-throws">Function <code>boost::throws()</code></a></h2>
<pre>system::error_code&amp; throws();</pre>
<blockquote>
<p><i>Returns:</i> A <code>system::error_code</code> reference
for use in some user-defined function signature as a &quot;throw on error&quot; tag.</p>
<p><i>Remark:</i> The only valid use for the returned reference is to test its
address for equality or inequality to the address of the reference returned by
another call to throws(). The returned reference itself has been poisoned so
that an attempt to dereference it will fail.</p>
<p>[<i>Example: </i>Example of a function that uses the <code>throws()</code> idiom:</p>
<blockquote>
<pre>int divide(int dividend, int divisor,
boost::system::error_code&amp; ec = boost::throws())
{
if (divisor == 0) // is there an error?
{
if (&amp;ec == &amp;boost::throws()) // throw on error
throw &quot;oops!&quot;; // whatever exception you prefer
ec = error_code(EDOM, generic_category()); // report error via error_code
return 0;
}
if (&amp;ec != &amp;boost::throws()) // error reporting via error_code
ec.clear();
return dividend / divisor;
}</pre>
</blockquote>
<p>&mdash; <i>end Example</i>]</p>
</blockquote>
<h2><a name="Header-system_error">Header &lt;boost/system/system_error.hpp&gt;</a></h2>
<h3><a name="Class-system_error">Class <code>
@ -818,7 +822,7 @@ application program interfaces.</p>
<hr>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%B %d, %Y" startspan -->January 06, 2014<!--webbot bot="Timestamp" endspan i-checksum="31400" --> </font>
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%B %d, %Y" startspan -->September 07, 2017<!--webbot bot="Timestamp" endspan i-checksum="38006" --> </font>
</p>
<p><EFBFBD> Copyright Beman Dawes, 2006, 2007, 2008, 2013</p>

View File

@ -56,6 +56,50 @@ namespace
ss >> s;
BOOST_TEST( s == expected );
}
// throws_function_test ------------------------------------------------------------//
// usage example
int divide(int dividend, int divisor, boost::system::error_code& ec = boost::throws())
{
if (divisor == 0) // is there an error?
{
if (&ec == &boost::throws()) // throw on error
throw "oops!"; // whatever exception you prefer
ec = error_code(EDOM, generic_category()); // report error via error_code
return 0;
}
if (&ec != &boost::throws()) // error reporting via error_code
ec.clear();
return dividend / divisor;
}
// test usage example
void test_throws_usage()
{
std::cout << "Test throws() example and usage...\n";
error_code ec;
// no error tests
BOOST_TEST_EQ((divide(10, 2)), 5); // no error, report via exception
ec = make_error_code(errc::argument_out_of_domain);
BOOST_TEST_EQ((divide(10, 5, ec)), 2); // no error, report via error_code
BOOST_TEST(!ec);
ec = make_error_code(errc::argument_out_of_domain);
BOOST_TEST_EQ((divide(10, 0, ec)), 0); // error, report via error_code
BOOST_TEST(ec);
bool exception_thrown = false;
try
{ divide(10, 0); } // error, report via exception
catch (...)
{ exception_thrown = true; }
BOOST_TEST(exception_thrown);
}
}
// main ------------------------------------------------------------------------------//
@ -202,6 +246,8 @@ int main( int, char ** )
BOOST_TEST( econd.message() != "" );
BOOST_TEST( econd.message().substr( 0, 13) != "Unknown error" );
test_throws_usage();
#ifdef BOOST_WINDOWS_API
std::cout << "Windows tests...\n";
// these tests probe the Windows errc decoder