Files
safe_numerics/doc/html/tutorial/7.html
Robert Ramey 63dd89210e Enabled Boost Book syntax highlighting
improved TOC and chunking.  This is complicated by the fact we that we desire different depths.
put copies of boost logo in subdirectories
2016-02-07 14:38:06 -08:00

174 lines
19 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.76.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="6.html" title="Checking of Input Values Can Be Easily Overlooked">
<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="6.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.7"></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 has been proposed as an addition to the C++
language [<a class="citation" href="bibliography.html#idm413202501360"><span class="citation">Garcia</span></a>][<span class="citation">Crowl &amp;
Ottosen</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 guarantee 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="string">"../include/safe_range.hpp"</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">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 numeric to enforce program contract automatically</span>
<span class="comment">// define convient 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">numeric</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">numeric</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">safe_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 for checking as parameters are guaranteed to be within limits</span>
<span class="comment">// expression below cannot throw ! zero runtime overhead</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">int</span> <span class="identifier">main</span><span class="special">(</span><span class="keyword">int</span> <span class="identifier">argc</span><span class="special">,</span> <span class="keyword">const</span> <span class="keyword">char</span> <span class="special">*</span> <span class="identifier">argv</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="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Not using safe numerics"</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="comment">// problem: checking of externally produced value can be expensive</span>
<span class="keyword">try</span> <span class="special">{</span>
<span class="identifier">convert</span><span class="special">(</span><span class="number">10</span><span class="special">,</span> <span class="number">83</span><span class="special">)</span><span class="special">;</span> <span class="comment">// invalid parameters - detected - but at a heavy cost</span>
<span class="special">}</span>
<span class="keyword">catch</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</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">"exception thrown for parameter error"</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="comment">// solution: use safe range to restrict parameters</span>
<span class="identifier">std</span><span class="special">::</span><span class="identifier">cout</span> <span class="special">&lt;&lt;</span> <span class="string">"Using safe numerics"</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">try</span> <span class="special">{</span>
<span class="comment">// parameters are guarenteed to meet requirements</span>
<span class="identifier">hours_t</span> <span class="identifier">hours</span><span class="special">(</span><span class="number">10</span><span class="special">)</span><span class="special">;</span>
<span class="identifier">minutes_t</span> <span class="identifier">minutes</span><span class="special">(</span><span class="number">83</span><span class="special">)</span><span class="special">;</span> <span class="comment">// interrupt thrown here</span>
<span class="comment">// so the following will never throw</span>
<span class="identifier">safe_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">catch</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</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">"exception thrown when invalid arguments are constructed"</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="comment">// parameters are guarenteed to meet requirements when</span>
<span class="comment">// constructed on the stack</span>
<span class="identifier">safe_convert</span><span class="special">(</span><span class="identifier">hours_t</span><span class="special">(</span><span class="number">10</span><span class="special">)</span><span class="special">,</span> <span class="identifier">minutes_t</span><span class="special">(</span><span class="number">83</span><span class="special">)</span><span class="special">)</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">catch</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</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">"exception thrown when invalid arguments are constructed on the stack"</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="comment">// parameters are guarenteed to meet requirements when</span>
<span class="comment">// implicitly constructed to safe types to match function signature</span>
<span class="identifier">safe_convert</span><span class="special">(</span><span class="number">10</span><span class="special">,</span> <span class="number">83</span><span class="special">)</span><span class="special">;</span>
<span class="special">}</span>
<span class="keyword">catch</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</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">"exception thrown when invalid arguments are implicitly constructed"</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="comment">// the following will never throw as the values meet requirements.</span>
<span class="keyword">const</span> <span class="identifier">hours_t</span> <span class="identifier">hours</span><span class="special">(</span><span class="number">10</span><span class="special">)</span><span class="special">;</span>
<span class="keyword">const</span> <span class="identifier">minutes_t</span> <span class="identifier">minutes</span><span class="special">(</span><span class="number">17</span><span class="special">)</span><span class="special">;</span>
<span class="comment">// note zero runtime overhead once values are constructed</span>
<span class="comment">// the following will never throw because it cannot be called with</span>
<span class="comment">// invalid parameters</span>
<span class="identifier">safe_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="comment">// zero runtime overhead</span>
<span class="comment">// since safe types can be converted to their underlying unsafe types</span>
<span class="comment">// we can still call an unsafe function with safe types</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="comment">// zero (depending on compiler) runtime overhead</span>
<span class="comment">// since unsafe types can be implicitly converted to corresponding</span>
<span class="comment">// safe types we can just pass the unsafe types. checkin will occur</span>
<span class="comment">// when the safe type is constructed.</span>
<span class="identifier">safe_convert</span><span class="special">(</span><span class="number">10</span><span class="special">,</span> <span class="number">17</span><span class="special">)</span><span class="special">;</span> <span class="comment">// runtime cost in creating parameters</span>
<span class="special">}</span>
<span class="keyword">catch</span><span class="special">(</span><span class="identifier">std</span><span class="special">::</span><span class="identifier">exception</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">"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">return</span> <span class="number">0</span><span class="special">;</span>
<span class="special">}</span>
</pre>
<p>In the example above the function convert incurs significant runtime
cost every time the function is called. By using "safe" types, this cost
is moved to 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 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="6.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>