Click here to Skip to main content
15,896,434 members
Articles / Programming Languages / C++

Writing an exception safe code in generic way.

Rate me:
Please Sign up or sign in to vote.
4.88/5 (11 votes)
12 Dec 20069 min read 40.9K   326   36  
An article on how to change the way of writing exception-safe code.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<title>am::mate: Basic usage.</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="tabs.css" rel="stylesheet" type="text/css">
</head><body>
<!-- Generated by Doxygen 1.5.1 -->
<div class="tabs">
  <ul>
    <li><a href="index.html"><span>Main&nbsp;Page</span></a></li>
    <li><a href="namespaces.html"><span>Namespaces</span></a></li>
    <li><a href="annotated.html"><span>Classes</span></a></li>
    <li><a href="files.html"><span>Files</span></a></li>
    <li><a href="pages.html"><span>Related&nbsp;Pages</span></a></li>
  </ul></div>
<div class="nav">
<a class="el" href="index.html">Writing an exception safe code in generic way.</a></div>
<h1><a class="anchor" name="mate_basic_usage">Basic usage.</a></h1><h2><a class="anchor" name="mate_bu_s1">
Mating a host function call with a mate function.</a></h2>
Mating a host function call with a mate function is easy. Provide the host function as the first argument (by calling it) and the mate function as the second argument of the constructor of the <a class="el" href="classam_1_1mate.html">am::mate</a> variable. Specifies the return type of the host function explicitly as the template argument of the <a class="el" href="classam_1_1mate.html">am::mate</a> when declaring it.<p>
Use <a class="el" href="mate_8hpp.html#01562e931d80813b43fcddc1a13799fe">MATE()</a> macro to create an anonymous <a class="el" href="classam_1_1mate.html">am::mate</a> variable when you are not concerning about using <a class="el" href="classam_1_1mate.html">am::mate</a> variable.<p>
<div class="fragment"><pre class="fragment"> <span class="keywordtype">int</span> prefix(<span class="keywordtype">int</span> n) { <span class="keywordflow">return</span> n + 100; }
 <span class="keywordtype">void</span> suffix(<span class="keywordtype">int</span> n) { n -= 100; }

 <span class="keywordtype">void</span> test04()
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;int&gt;</a> nNumber( prefix(123), &amp;suffix );
   assert( 23 == nNumber );

   <span class="keywordtype">int</span> nNumber2 = nNumber; <span class="comment">// Compile OK!</span>

<span class="preprocessor"> #if 0</span>
<span class="preprocessor"></span>   nNumber = nNumber2; <span class="comment">// Compile error! mate is non-assignable.</span>
   nNumber = 52;       <span class="comment">// Compile error! mate is non-assignable.</span>
<span class="preprocessor"> #endif</span>
<span class="preprocessor"></span>
  {
    <a class="code" href="mate_8hpp.html#01562e931d80813b43fcddc1a13799fe">MATE</a>( prefix( 333 ), &amp;suffix );

  } <span class="comment">// calls suffix( 233 ) here</span>

 } <span class="comment">// calls suffix( 23 ) here on exit.</span>
</pre></div><p>
An <a class="el" href="classam_1_1mate.html">am::mate</a> variable can be treated as a variable of the data type of which is specified as the template parameter when the <a class="el" href="classam_1_1mate.html">am::mate</a> variable is declared. This is due to the implict conversion operator to the data type. But also be aware that it is read-only access, which means it behaves like a const variable. i.e. an <code>am::mate&lt;int&gt;</code> variable can be treated as a <code>const int</code> variable.<h2><a class="anchor" name="mate_bu_s2">
Composing a mate fuction object.</a></h2>
Mate function object will take the return of the host function as its only input argument (it should be an unary function object) when it is called. You can use any known techniques to compose and provide an unary custom function object when constructing <a class="el" href="classam_1_1mate.html">am::mate</a> variable.<p>
<div class="fragment"><pre class="fragment"> <span class="keyword">struct </span>MyReleaseDC
 {
   HWND hwnd_;
   MyReleaseDC(HWND hwnd) : hwnd_( hwnd ) { }
   <span class="keywordtype">int</span> operator ()(HDC hdc)<span class="keyword"> const </span>{ return ::ReleaseDC( hwnd_, hdc ); }

 };  <span class="comment">// struct MyReleaseDC</span>

 <span class="keyword">struct </span>MySelectObject
 {
   HDC hdc_;
   MySelectObject(HDC hdc) : hdc_( hdc ) { }
   HGDIOBJ operator ()(HGDIOBJ hgdiobj)<span class="keyword"> const </span>{ return ::SelectObject( hdc_, hgdiobj ); }

 };  <span class="comment">// struct MySelectObject</span>

 <span class="keywordtype">void</span> test05(HWND hwnd)
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;HDC&gt;</a> hdc( ::GetWindowDC( hwnd ), MyReleaseDC( hwnd ) );

   <a class="code" href="mate_8hpp.html#01562e931d80813b43fcddc1a13799fe">MATE</a>( ::SelectObject( hdc, ::GetStockObject( BLACK_PEN ) ), MySelectObject( hdc ) );
 } 
</pre></div><p>
<div class="fragment"><pre class="fragment"><span class="preprocessor"> #define BOOST_BIND_ENABLE_STDCALL</span>
<span class="preprocessor"></span><span class="preprocessor"> #include &lt;boost/bind.hpp&gt;</span>

 <span class="keywordtype">void</span> test06(HWND hwnd)
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;HDC&gt;</a> hdc( ::GetWindowDC( hwnd ), <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">boost::bind</a>( &amp;::ReleaseDC, hwnd, <a class="code" href="namespaceam_1_1lambda.html#46cdab44274e0a15a02179cade2f0bb4">_1</a> ) );

   <a class="code" href="mate_8hpp.html#01562e931d80813b43fcddc1a13799fe">MATE</a>( ::SelectObject( hdc, ::GetStockObject( BLACK_PEN ) ), <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">boost::bind</a>( &amp;::SelectObject, hdc, <a class="code" href="namespaceam_1_1lambda.html#46cdab44274e0a15a02179cade2f0bb4">_1</a> ) );
 }
</pre></div><p>
<div class="fragment"><pre class="fragment"> <span class="keywordtype">void</span> test07(HWND hwnd)
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;HDC&gt;</a> hdc( ::GetWindowDC( hwnd ), <a class="code" href="namespaceam.html#5d35d0139360afc672d2cf1ff279fd83">am::bind1st</a>( &amp;::ReleaseDC, hwnd ) );

   <a class="code" href="mate_8hpp.html#01562e931d80813b43fcddc1a13799fe">MATE</a>( ::SelectObject( hdc, ::GetStockObject( BLACK_PEN ) ), <a class="code" href="namespaceam.html#5d35d0139360afc672d2cf1ff279fd83">am::bind1st</a>( &amp;::SelectObject, hdc ) );
 }
</pre></div><p>
<div class="fragment"><pre class="fragment"><span class="preprocessor"> #define AM_BIND_ENABLE_STDCALL</span>
<span class="preprocessor"></span><span class="preprocessor"> #include "<a class="code" href="lambda_8hpp.html">lambda.hpp</a>"</span>

 <span class="keywordtype">void</span> test08(HWND hwnd)
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;HDC&gt;</a> hdc( ::GetWindowDC( hwnd ), <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a>( &amp;::ReleaseDC, hwnd, <a class="code" href="namespaceam_1_1lambda.html#46cdab44274e0a15a02179cade2f0bb4">am::lambda::_1</a> ) );

   <a class="code" href="mate_8hpp.html#01562e931d80813b43fcddc1a13799fe">MATE</a>( ::SelectObject( hdc, ::GetStockObject( BLACK_PEN ) ),
     <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a>( &amp;::SelectObject, hdc, <a class="code" href="namespaceam_1_1lambda.html#46cdab44274e0a15a02179cade2f0bb4">am::lambda::_1</a> ) );
 }
</pre></div><h2><a class="anchor" name="mate_bu_s3">
Mating with a condition.</a></h2>
Sometime there are cases in which the host function call might be failed and returns the error code as a result. In such cases, the mate function should not be called. Checking the error of the host function call can be easily performed as <a class="el" href="classam_1_1mate.html">am::mate</a> variable can be treated as a const variable of the return type of the host function call. Use dismate_mate() member function to dismiss the mate function call.<p>
<div class="fragment"><pre class="fragment"> <span class="keywordtype">void</span> test09()
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;HANDLE&gt;</a> hEvent( ::CreateEvent( NULL, FALSE, FALSE, NULL ), &amp;::CloseHandle );
   <span class="keywordflow">if</span>( hEvent == NULL )
     hEvent.dismiss_mate();

 }
</pre></div><p>
However this approach can not be used with <a class="el" href="mate_8hpp.html#01562e931d80813b43fcddc1a13799fe">MATE()</a> macro. Use <a class="el" href="mate_8hpp.html#9017d939bd69b57ffa03347874ac607b">MATE_IF()</a> macro instead and provides a unary predicate as the third input argument for a condition. <a class="el" href="mate_8hpp.html#9017d939bd69b57ffa03347874ac607b">MATE_IF()</a> utilizes <a class="el" href="classam_1_1mate.html">am::mate</a>'s another constructor which takes an unary predicate as its third input argument. If a condition is provided, the mate function will be called, when it goes out of scope, only if the provided unary predicate asserts true.<p>
The unary predicate takes the return of the host function as its only input argument as well. Like mate function object, you can compose a unary predicate in any techniques you know of.<p>
<div class="fragment"><pre class="fragment"> <span class="keyword">struct </span>EventCreated
 {
   <span class="keywordtype">bool</span> operator ()(HANDLE hevent)<span class="keyword"> const </span>{ <span class="keywordflow">return</span> NULL != hevent; }

 };  <span class="comment">// struct EventCreated</span>

 <span class="keywordtype">void</span> test10()
 {
   <a class="code" href="mate_8hpp.html#9017d939bd69b57ffa03347874ac607b">MATE_IF</a>( ::CreateEvent( NULL, FALSE, FALSE, NULL ), &amp;::CloseHandle,  EventCreated() );

 }
</pre></div><p>
There is one advantage of using <a class="el" href="classam_1_1mate.html">am::mate</a> with a condition than without a condition. When a mate function object is stored into the <a class="el" href="classam_1_1mate.html">am::mate</a> variable internally, the heap memory allocation is occurred. But if the condition does not hold, nor will the heap memory allocation occur since the mate function will not be called.<p>
<div class="fragment"><pre class="fragment"> <span class="keywordtype">void</span> test11()
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;HANDLE&gt;</a> hEvent( ::CreateEvent( NULL, FALSE, FALSE, NULL ),
     &amp;::CloseHandle, (HANDLE)NULL != <a class="code" href="namespaceam_1_1lambda.html#46cdab44274e0a15a02179cade2f0bb4">am::lambda::_1</a> );

 }
</pre></div><h2><a class="anchor" name="mate_bu_s4">
am::mate&lt;void&gt; specialization.</a></h2>
If the mate function does not concern about the return of the host function which is given as its input argument, you can write a mate fuction object which takes the return of the host function, but then simply ignores it.<p>
<div class="fragment"><pre class="fragment"><span class="preprocessor"> #define RESOURCE_ACQUSITION_SUCCESS 100</span>
<span class="preprocessor"></span><span class="preprocessor"> #define RESOURCE_ACQUSITION_FAIL    200</span>
<span class="preprocessor"></span>
 <span class="keywordtype">int</span> AcquireResource(HANDLE hres) { <span class="keywordflow">return</span> RESOURCE_ACQUSITION_SUCCESS; }
 <span class="keywordtype">void</span> ReleaseResource(HANDLE hres) { }

 <span class="keyword">struct </span>IgnoreReturnAndReleaseResource
 {
   HANDLE hres_;
   IgnoreReturnAndReleaseResource(HANDLE hres) : hres_( hres ) { }
   <span class="keywordtype">void</span> operator ()(<span class="keywordtype">int</span>)<span class="keyword"> const </span>{ ReleaseResource( hres_ ); }

 };  <span class="comment">// struct IgnoreReturnAndReleaseResource</span>

 <span class="keywordtype">void</span> test12(HANDLE hres)
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;int&gt;</a> nResult( AcquireResource( hres ),
     IgnoreReturnAndReleaseResource( hres ), RESOURCE_ACQUSITION_SUCCESS == <a class="code" href="namespaceam_1_1lambda.html#46cdab44274e0a15a02179cade2f0bb4">am::lambda::_1</a>  );

 } <span class="comment">// Calls ReleaseResource( hres ) on exit if AcquireResource( hres ) returns RESOURCE_ACQUSITION_SUCCESS</span>
</pre></div><p>
If you use <code>boost::bind</code>, <code>boost::lambda::bind</code> or <a class="el" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a> to compose a function object in the way that all of its input arguments are bound. It will automatically create an unary function object that simply ignores the return of the host function, and when it is called, it will call the mate function only with all those bound input arguments.<p>
<div class="fragment"><pre class="fragment"><span class="preprocessor"> #define RESOURCE_ACQUSITION_SUCCESS 100</span>
<span class="preprocessor"></span><span class="preprocessor"> #define RESOURCE_ACQUSITION_FAIL    200</span>
<span class="preprocessor"></span>
 <span class="keywordtype">int</span> AcquireResource(HANDLE hres) { <span class="keywordflow">return</span> RESOURCE_ACQUSITION_SUCCESS; }
 <span class="keywordtype">void</span> ReleaseResource(HANDLE hres) { }

 <span class="keywordtype">void</span> test13(HANDLE hres)
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;int&gt;</a> nResult( AcquireResource( hres ),
     <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a>( &amp;ReleaseResource, hres ), RESOURCE_ACQUSITION_SUCCESS == <a class="code" href="namespaceam_1_1lambda.html#46cdab44274e0a15a02179cade2f0bb4">am::lambda::_1</a>  );

 }
</pre></div><p>
If the host function is a function with void return or even we don't have a host function to call at all, <a class="el" href="classam_1_1mate_3_01void_01_4.html">am::mate&lt;void&gt;</a> specialization and <a class="el" href="mate_8hpp.html#b64fb21cccc9097c72ddab9f2c37d78a">MATE_VOID()</a> macro play a neat role in such cases as <a class="el" href="classam_1_1mate_3_01void_01_4.html">am::mate&lt;void&gt;</a> class' constructors do not take the return of host function as their first argument.<p>
<div class="fragment"><pre class="fragment"> <span class="keywordtype">void</span> AcquireResourceEx(HANDLE hres) { }
 <span class="keywordtype">void</span> ReleaseResourceEx(HANDLE hres) { }
 <span class="keywordtype">void</span> Cleanup() { }

 <span class="keywordtype">void</span> test14(HANDLE hres, <span class="keywordtype">int</span> option)
 {
   <a class="code" href="classam_1_1mate.html">am::mate&lt;void&gt;</a> cleanup_on_exit( &amp;Cleanup );

   <span class="keywordflow">if</span>( 0 == option )
   {
     AcquireResourceEx( hres );
     <a class="code" href="mate_8hpp.html#b64fb21cccc9097c72ddab9f2c37d78a">MATE_VOID</a>( <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a>( &amp;ReleaseResourceEx, hres ) );

   }
   <span class="keywordflow">else</span> <span class="keywordflow">if</span>( 1 == option )
   {
     AcquireResourceEx( hres );
     <a class="code" href="mate_8hpp.html#becd3ca3f114b18666fd383aad100fef">MATE_VOID_IF</a>( <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a>( &amp;ReleaseResourceEx, hres ), <a class="code" href="structam_1_1condition.html">am::condition</a>( NULL != hres ) );

   }
   <span class="keywordflow">else</span> <span class="keywordflow">if</span>( 2 == option )
   {
     <a class="code" href="classam_1_1mate.html">am::mate&lt;void&gt;</a> dummy( ( AcquireResourceEx( hres ), <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a>( &amp;ReleaseResourceEx, hres ) ) );

   }
   <span class="keywordflow">else</span> <span class="keywordflow">if</span>( 3 == option )
   {
     <a class="code" href="classam_1_1mate.html">am::mate&lt;void&gt;</a> dummy( ( AcquireResourceEx( hres ), <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a>( &amp;ReleaseResourceEx, hres ) ),
       <a class="code" href="structam_1_1condition.html">am::condition</a>( NULL != hres ) );

   }
   <span class="keywordflow">else</span>
   {
     <a class="code" href="mate_8hpp.html#b64fb21cccc9097c72ddab9f2c37d78a">MATE_VOID</a>( ( AcquireResourceEx( hres ), <a class="code" href="namespaceam_1_1lambda.html#794d3c4a2b7231c36cfc0684fea9bf5e">am::lambda::bind</a>( &amp;ReleaseResourceEx, hres ) ) );

   }
 }
</pre></div><p>
It is possible to use comma (,) operator between the host function call and the mate function and then wrap them with the nested parenthesis to make it look and feel the same style as non-void <a class="el" href="classam_1_1mate.html">am::mate</a>.<p>
<a class="el" href="index.html#mate_contents">[Contents]</a> <hr size="1"><address style="align: right;"><small>Generated on Sat Dec 16 22:27:43 2006 for am::mate by&nbsp;
<a href="http://www.doxygen.org/index.html">
<img src="doxygen.png" alt="doxygen" align="middle" border="0"></a> 1.5.1 </small></address>
</body>
</html>

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Other
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions