boost/libs/convert/doc/html/boost_convert/error_detection.html
2021-10-05 21:37:46 +02:00

183 lines
18 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Better Error Detection</title>
<link rel="stylesheet" href="../../../../../doc/src/boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Chapter 1. Boost.Convert 2.0">
<link rel="up" href="../index.html" title="Chapter 1. Boost.Convert 2.0">
<link rel="prev" href="getting_started/basic_conversion_failure_detection.html" title="Basic Conversion-Failure Detection">
<link rel="next" href="default_converter.html" title="Default Converter">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img alt="Boost C++ Libraries" width="277" height="86" src="../../../../../boost.png"></td>
<td align="center"><a href="../../../../../index.html">Home</a></td>
<td align="center"><a href="../../../../../libs/libraries.htm">Libraries</a></td>
<td align="center"><a href="http://www.boost.org/users/people.html">People</a></td>
<td align="center"><a href="http://www.boost.org/users/faq.html">FAQ</a></td>
<td align="center"><a href="../../../../../more/index.htm">More</a></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="getting_started/basic_conversion_failure_detection.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="default_converter.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="boost_convert.error_detection"></a><a class="link" href="error_detection.html" title="Better Error Detection">Better Error Detection</a>
</h2></div></div></div>
<div class="blockquote"><blockquote class="blockquote"><p>
<span class="bold"><strong><span class="emphasis"><em>"Detection is, or ought to be, an exact
science, ..." Sir Arthur Conan Doyle</em></span></strong></span>
</p></blockquote></div>
<p>
</p>
<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">i2</span> <span class="special">=</span> <span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="string">"not an int"</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">).</span><span class="identifier">value_or</span><span class="special">(-</span><span class="number">1</span><span class="special">);</span> <span class="comment">// after the call i2==-1</span>
<span class="keyword">if</span> <span class="special">(</span><span class="identifier">i2</span> <span class="special">==</span> <span class="special">-</span><span class="number">1</span><span class="special">)</span> <span class="identifier">process_failure</span><span class="special">();</span>
</pre>
<p>
</p>
<p>
The code above is straightforward and self-explanatory but, strictly speaking,
is not entirely correct as -1 might be the result of a conversion failure or
the successful conversion of the "-1" string. Still, in reality "spare"
values (outside the valid/sensible range) are often available to indicate conversion
failures. If so, such straightorward deployment might be adequate. Alternatively,
it might be not that uncommon to ignore conversion failures altogether and
to simply log the event and to proceed with the supplied fallback value.
</p>
<p>
Applications outside these mentioned categories still require conversion failure
reliably detected and processed accordingly. The <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">lexical_cast</span></code>'s
(only) answer is to throw on failure and <span class="emphasis"><em>Boost.Convert</em></span>
supports that behavior as well:
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">try</span>
<span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">i1</span> <span class="special">=</span> <span class="identifier">lexical_cast</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str</span><span class="special">);</span> <span class="comment">// Throws if the conversion fails.</span>
<span class="keyword">int</span> <span class="identifier">i2</span> <span class="special">=</span> <span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">).</span><span class="identifier">value</span><span class="special">();</span> <span class="comment">// Throws if the conversion fails.</span>
<span class="special">}</span>
<span class="keyword">catch</span> <span class="special">(...)</span>
<span class="special">{</span>
<span class="identifier">process_failure</span><span class="special">();</span>
<span class="special">}</span>
</pre>
<p>
</p>
<p>
However, to cater for a wider range of program-flow variations, <span class="emphasis"><em>Boost.Convert</em></span>
adds the flexibility of
</p>
<div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; ">
<li class="listitem">
delaying the moment when the conversion-failure exception is actually thrown
or
</li>
<li class="listitem">
avoiding the exception altogether.
</li>
</ul></div>
<p>
</p>
<pre class="programlisting"><span class="identifier">optional</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">r1</span> <span class="special">=</span> <span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str1</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">);</span> <span class="comment">// Does not throw on conversion failure.</span>
<span class="identifier">optional</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">r2</span> <span class="special">=</span> <span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str2</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">);</span> <span class="comment">// Does not throw on conversion failure.</span>
<span class="comment">// ...</span>
<span class="keyword">try</span> <span class="comment">// Delayed processing of potential exceptions.</span>
<span class="special">{</span>
<span class="keyword">int</span> <span class="identifier">i1</span> <span class="special">=</span> <span class="identifier">r1</span><span class="special">.</span><span class="identifier">value</span><span class="special">();</span> <span class="comment">// Will throw if conversion failed.</span>
<span class="keyword">int</span> <span class="identifier">i2</span> <span class="special">=</span> <span class="identifier">r2</span><span class="special">.</span><span class="identifier">value</span><span class="special">();</span> <span class="comment">// Will throw if conversion failed.</span>
<span class="special">}</span>
<span class="keyword">catch</span> <span class="special">(</span><span class="identifier">boost</span><span class="special">::</span><span class="identifier">bad_optional_access</span> <span class="keyword">const</span><span class="special">&amp;)</span>
<span class="special">{</span>
<span class="comment">// Handle failed conversion.</span>
<span class="special">}</span>
<span class="comment">// Exceptions are avoided altogether.</span>
<span class="keyword">int</span> <span class="identifier">i1</span> <span class="special">=</span> <span class="identifier">r1</span> <span class="special">?</span> <span class="identifier">r1</span><span class="special">.</span><span class="identifier">value</span><span class="special">()</span> <span class="special">:</span> <span class="identifier">fallback_value</span><span class="special">;</span>
<span class="keyword">int</span> <span class="identifier">i2</span> <span class="special">=</span> <span class="identifier">r2</span><span class="special">.</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback_value</span><span class="special">);</span>
<span class="keyword">int</span> <span class="identifier">i3</span> <span class="special">=</span> <span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str3</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">).</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback_value</span><span class="special">);</span>
<span class="keyword">int</span> <span class="identifier">i4</span> <span class="special">=</span> <span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str3</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">).</span><span class="identifier">value_or_eval</span><span class="special">(</span><span class="identifier">fallback_function</span><span class="special">);</span>
</pre>
<p>
</p>
<p>
Here <a href="../../../../../libs/optional/index.html" target="_top"><code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span></code></a>
steps forward as the actual type returned by <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">()</span></code> which until now we avoided by immediately
calling its value-accessor methods:
</p>
<pre class="programlisting"><span class="keyword">int</span> <span class="identifier">i1</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str1</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">).</span><span class="identifier">value</span><span class="special">();</span>
<span class="keyword">int</span> <span class="identifier">i2</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str2</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">).</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback_value</span><span class="special">);</span>
<span class="keyword">int</span> <span class="identifier">i3</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str3</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">).</span><span class="identifier">value_or_eval</span><span class="special">(</span><span class="identifier">fallback_function</span><span class="special">);</span>
</pre>
<div class="note"><table border="0" summary="Note">
<tr>
<td rowspan="2" align="center" valign="top" width="25"><img alt="[Note]" src="../../../../../doc/src/images/note.png"></td>
<th align="left">Note</th>
</tr>
<tr><td align="left" valign="top"><p>
One notable advantage of <code class="computeroutput"><span class="identifier">value_or_eval</span><span class="special">()</span></code> over <code class="computeroutput"><span class="identifier">value_or</span><span class="special">()</span></code> is that the actual calculation of the
<code class="computeroutput"><span class="identifier">fallback_value</span></code> is potentially
delayed and conditional on the success or failure of the conversion.
</p></td></tr>
</table></div>
<p>
From the user perspective, <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">lexical_cast</span></code>
processes failure in a somewhat one-dimensional non-negotiable manner. <code class="computeroutput"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span></code>
takes a more flexible approach. It provides choice and leaves the decision
to the user. It is not unimaginable that, on the library level, propagating
the conversion-failure exception might be the only available option. On the
application level though, in my personal experience, the choice has overwhelmingly
been to handle conversion failures <span class="emphasis"><em>locally</em></span>, i.e. avoiding
conversion-failure exception propagation or, better still, avoiding exceptions
altogether with program flows similar to:
</p>
<p>
</p>
<pre class="programlisting"><span class="identifier">boost</span><span class="special">::</span><span class="identifier">optional</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;</span> <span class="identifier">res</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">);</span>
<span class="keyword">if</span> <span class="special">(!</span><span class="identifier">res</span><span class="special">)</span> <span class="identifier">log</span><span class="special">(</span><span class="string">"str conversion failed!"</span><span class="special">);</span>
<span class="keyword">int</span> <span class="identifier">i1</span> <span class="special">=</span> <span class="identifier">res</span><span class="special">.</span><span class="identifier">value_or</span><span class="special">(</span><span class="identifier">fallback_value</span><span class="special">);</span>
<span class="comment">// ...proceed</span>
</pre>
<p>
</p>
<p>
and
</p>
<p>
</p>
<pre class="programlisting"><span class="keyword">struct</span> <span class="identifier">fallback_func</span>
<span class="special">{</span>
<span class="keyword">int</span> <span class="keyword">operator</span><span class="special">()()</span> <span class="keyword">const</span> <span class="special">{</span> <span class="identifier">log</span><span class="special">(</span><span class="string">"Failed to convert"</span><span class="special">);</span> <span class="keyword">return</span> <span class="number">42</span><span class="special">;</span> <span class="special">}</span>
<span class="special">};</span>
</pre>
<p>
</p>
<p>
</p>
<pre class="programlisting"><span class="comment">// Fallback function is called when failed</span>
<span class="keyword">int</span> <span class="identifier">i2</span> <span class="special">=</span> <span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">).</span><span class="identifier">value_or_eval</span><span class="special">(</span><span class="identifier">fallback_func</span><span class="special">());</span>
<span class="keyword">int</span> <span class="identifier">i3</span> <span class="special">=</span> <span class="identifier">convert</span><span class="special">&lt;</span><span class="keyword">int</span><span class="special">&gt;(</span><span class="identifier">str</span><span class="special">,</span> <span class="identifier">cnv</span><span class="special">,</span> <span class="identifier">fallback_func</span><span class="special">());</span> <span class="comment">// Same as above. Alternative API.</span>
</pre>
<p>
</p>
</div>
<table xmlns:rev="http://www.cs.rpi.edu/~gregod/boost/tools/doc/revision" width="100%"><tr>
<td align="left"></td>
<td align="right"><div class="copyright-footer">Copyright © 2009-2020 Vladimir Batov<p>
Distributed under the Boost Software License, Version 1.0. See copy at <a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">http://www.boost.org/LICENSE_1_0.txt</a>.
</p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="getting_started/basic_conversion_failure_detection.html"><img src="../../../../../doc/src/images/prev.png" alt="Prev"></a><a accesskey="u" href="../index.html"><img src="../../../../../doc/src/images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../../../../../doc/src/images/home.png" alt="Home"></a><a accesskey="n" href="default_converter.html"><img src="../../../../../doc/src/images/next.png" alt="Next"></a>
</div>
</body>
</html>