safe_numerics/doc/html/tutorial/10.html
2019-02-24 09:54:13 -08:00

146 lines
18 KiB
HTML

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Programming by Contract is Too Slow</title>
<link rel="stylesheet" href="../boostbook.css" type="text/css">
<meta name="generator" content="DocBook XSL Stylesheets V1.79.1">
<link rel="home" href="../index.html" title="Safe Numerics">
<link rel="up" href="../tutorial.html" title="Tutorial and Motivating Examples">
<link rel="prev" href="9.html" title="Compile Time Arithmetic is Not Always Correct">
<link rel="next" href="../eliminate_runtime_penalty.html" title="Eliminating Runtime Penalty">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<table cellpadding="2" width="100%"><tr>
<td valign="top"><img href="index.html" height="164px" src="pre-boost.jpg" alt="Library Documentation Index"></td>
<td><h2>Safe Numerics</h2></td>
</tr></table>
<div class="spirit-nav">
<a accesskey="p" href="9.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../eliminate_runtime_penalty.html"><img src="../images/next.png" alt="Next"></a>
</div>
<div class="section">
<div class="titlepage"><div><div><h3 class="title">
<a name="safe_numerics.tutorial.10"></a>Programming by Contract is Too Slow</h3></div></div></div>
<p>Programming by Contract is a highly regarded technique. There has
been much written about it and it has been proposed as an addition to the
C++ language [<span class="citation"><a class="xref" href="bibliography.html#garcia" title="C++ language support for contract programming"><abbr class="abbrev">Garcia</abbr></a></span>][<span class="citation"><a class="xref" href="bibliography.html#crowl2" title="Proposal to add Contract Programming to C++"><abbr class="abbrev">Crowl &amp; Ottosen</abbr></a></span>] It (mostly) depends upon runtime checking of
parameter and object values upon entry to and exit from every function.
This can slow the program down considerably which in turn undermines the
main motivation for using C++ in the first place! One popular scheme for
addressing this issue is to enable parameter checking only during
debugging and testing which defeats the guarantee of correctness which we
are seeking here! Programming by Contract will never be accepted by
programmers as long as it is associated with significant additional
runtime cost.</p>
<p>The Safe Numerics Library has facilities which, in many cases, can
check guaranteed parameter requirements with little or no runtime
overhead. Consider the following example:</p>
<pre class="programlisting"><span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">cassert</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">stdexcept</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">sstream</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">iostream</span><span class="special">&gt;</span>
<span class="preprocessor">#include</span> <span class="special">&lt;</span><span class="identifier">boost</span><span class="special">/</span><span class="identifier">safe_numerics</span><span class="special">/</span><span class="identifier">safe_integer_range</span><span class="special">.</span><span class="identifier">hpp</span><span class="special">&gt;</span>
<span class="comment">// NOT using safe numerics - enforce program contract explicitly</span>
<span class="comment">// return total number of minutes</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">contract_convert</span><span class="special">(</span>
<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="special">&amp;</span> <span class="identifier">hours</span><span class="special">,</span>
<span class="keyword">const</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="special">&amp;</span> <span class="identifier">minutes</span>
<span class="special">)</span> <span class="special">{</span>
<span class="comment">// check that parameters are within required limits</span>
<span class="comment">// invokes a runtime cost EVERYTIME the function is called</span>
<span class="comment">// and the overhead of supporting an interrupt.</span>
<span class="comment">// note high runtime cost!</span>
<span class="keyword">if</span><span class="special">(</span><span class="identifier">minutes</span> <span class="special">&gt;</span> <span class="number">59</span><span class="special">)</span>
<span class="keyword">throw</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">domain_error</span><span class="special">(</span><span class="string">"minutes exceeded 59"</span><span class="special">)</span><span class="special">;</span>
<span class="keyword">if</span><span class="special">(</span><span class="identifier">hours</span> <span class="special">&gt;</span> <span class="number">23</span><span class="special">)</span>
<span class="keyword">throw</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">domain_error</span><span class="special">(</span><span class="string">"hours exceeded 23"</span><span class="special">)</span><span class="special">;</span>
<span class="keyword">return</span> <span class="identifier">hours</span> <span class="special">*</span> <span class="number">60</span> <span class="special">+</span> <span class="identifier">minutes</span><span class="special">;</span>
<span class="special">}</span>
<span class="comment">// Use safe numerics to enforce program contract automatically</span>
<span class="comment">// define convenient typenames for hours and minutes hh:mm</span>
<span class="keyword">using</span> <span class="identifier">hours_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_unsigned_range</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span> <span class="number">23</span><span class="special">&gt;</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">minutes_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_unsigned_range</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span> <span class="number">59</span><span class="special">&gt;</span><span class="special">;</span>
<span class="keyword">using</span> <span class="identifier">minutes_total_t</span> <span class="special">=</span> <span class="identifier">boost</span><span class="special">::</span><span class="identifier">safe_numerics</span><span class="special">::</span><span class="identifier">safe_unsigned_range</span><span class="special">&lt;</span><span class="number">0</span><span class="special">,</span> <span class="number">59</span><span class="special">&gt;</span><span class="special">;</span>
<span class="comment">// return total number of minutes</span>
<span class="comment">// type returned is safe_unsigned_range&lt;0, 24*60 - 1&gt;</span>
<span class="keyword">auto</span> <span class="identifier">convert</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">hours_t</span> <span class="special">&amp;</span> <span class="identifier">hours</span><span class="special">,</span> <span class="keyword">const</span> <span class="identifier">minutes_t</span> <span class="special">&amp;</span> <span class="identifier">minutes</span><span class="special">)</span> <span class="special">{</span>
<span class="comment">// no need to test pre-conditions</span>
<span class="comment">// input parameters are guaranteed to hold legitimate values</span>
<span class="comment">// no need to test post-conditions</span>
<span class="comment">// return value guaranteed to hold result</span>
<span class="keyword">return</span> <span class="identifier">hours</span> <span class="special">*</span> <span class="number">60</span> <span class="special">+</span> <span class="identifier">minutes</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">test1</span><span class="special">(</span><span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">hours</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">minutes</span><span class="special">)</span><span class="special">{</span>
<span class="comment">// problem: checking of externally produced value can be expensive</span>
<span class="comment">// invalid parameters - detected - but at a heavy cost</span>
<span class="keyword">return</span> <span class="identifier">contract_convert</span><span class="special">(</span><span class="identifier">hours</span><span class="special">,</span> <span class="identifier">minutes</span><span class="special">)</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">auto</span> <span class="identifier">test2</span><span class="special">(</span><span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">hours</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">minutes</span><span class="special">)</span><span class="special">{</span>
<span class="comment">// solution: use safe numerics</span>
<span class="comment">// safe types can be implicitly constructed base types</span>
<span class="comment">// construction guarentees corectness</span>
<span class="comment">// return value is known to fit in unsigned int</span>
<span class="keyword">return</span> <span class="identifier">convert</span><span class="special">(</span><span class="identifier">hours</span><span class="special">,</span> <span class="identifier">minutes</span><span class="special">)</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">auto</span> <span class="identifier">test3</span><span class="special">(</span><span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">hours</span><span class="special">,</span> <span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">minutes</span><span class="special">)</span><span class="special">{</span>
<span class="comment">// actually we don't even need the convert function any more</span>
<span class="keyword">return</span> <span class="identifier">hours_t</span><span class="special">(</span><span class="identifier">hours</span><span class="special">)</span> <span class="special">*</span> <span class="number">60</span> <span class="special">+</span> <span class="identifier">minutes_t</span><span class="special">(</span><span class="identifier">minutes</span><span class="special">)</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">int</span> <span class="identifier">main</span><span class="special">(</span><span class="keyword">int</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span> <span class="special">*</span><span class="special">[</span><span class="special">]</span><span class="special">)</span><span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"example 7: "</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"enforce contracts with zero runtime cost"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="keyword">unsigned</span> <span class="keyword">int</span> <span class="identifier">total_minutes</span><span class="special">;</span>
<span class="keyword">try</span> <span class="special">{</span>
<span class="identifier">total_minutes</span> <span class="special">=</span> <span class="identifier">test3</span><span class="special">(</span><span class="number">17</span><span class="special">,</span> <span class="number">83</span><span class="special">)</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"total minutes = "</span> <span class="special">&lt;&lt;</span> <span class="identifier">total_minutes</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">catch</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="special">&amp;</span> <span class="identifier">e</span><span class="special">)</span><span class="special">{</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"parameter error detected"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">try</span> <span class="special">{</span>
<span class="identifier">total_minutes</span> <span class="special">=</span> <span class="identifier">test3</span><span class="special">(</span><span class="number">17</span><span class="special">,</span> <span class="number">10</span><span class="special">)</span><span class="special">;</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"total minutes = "</span> <span class="special">&lt;&lt;</span> <span class="identifier">total_minutes</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">catch</span><span class="special">(</span><span class="keyword">const</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</span> <span class="special">&amp;</span> <span class="identifier">e</span><span class="special">)</span><span class="special">{</span>
<span class="comment">// should never arrive here</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"parameter error erroneously detected"</span> <span class="special">&lt;&lt;</span> <span class="identifier">std</span><span class="special">::</span><span class="identifier">endl</span><span class="special">;</span>
<span class="keyword">return</span> <span class="number">1</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">return</span> <span class="number">0</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<pre class="screen">example 8:
enforce contracts with zero runtime cost
parameter error detected</pre>
<p>In the example above, the function <code class="computeroutput">convert</code> incurs
significant runtime cost every time the function is called. By using
"safe" types, this cost is moved to the moment when the parameters are
constructed. Depending on how the program is constructed, this may totally
eliminate extraneous computations for parameter requirement type checking.
In this scenario, there is no reason to suppress the checking for release
mode and our program can be guaranteed to be always arithmetically
correct.</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 &#169; 2012-2018 Robert Ramey<p><a href="http://www.boost.org/LICENSE_1_0.txt" target="_top">Subject to Boost
Software License</a></p>
</div></td>
</tr></table>
<hr>
<div class="spirit-nav">
<a accesskey="p" href="9.html"><img src="../images/prev.png" alt="Prev"></a><a accesskey="u" href="../tutorial.html"><img src="../images/up.png" alt="Up"></a><a accesskey="h" href="../index.html"><img src="../images/home.png" alt="Home"></a><a accesskey="n" href="../eliminate_runtime_penalty.html"><img src="../images/next.png" alt="Next"></a>
</div>
</body>
</html>