1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
<HTML>
<HEAD>
<TITLE>C++ guide</TITLE>
<LINK HREF="doxygen.css" REL="stylesheet" TYPE="text/css">
<LINK HREF="style_ini.css" REL="stylesheet" TYPE="text/css">
</HEAD>
<BODY BGCOLOR="#FFFFFF">
<A href="index.html">Home</A> ·
<A href="classes.html">Classes</A> ·
<A href="annotated.html">Annotated Classes</A> ·
<A href="modules.html">Modules</A> ·
<A href="functions_func.html">Members</A> ·
<A href="namespaces.html">Namespaces</A> ·
<A href="pages.html">Related Pages</A>
<HR style="height:1px; border:none; border-top:1px solid #c0c0c0;">
<!-- Generated by Doxygen 1.8.5 -->
</div><!-- top -->
<div class="header">
<div class="headertitle">
<div class="title">C++ guide </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><p>This file contains general C++ guidelines that are not OpenMS-specific.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">The 'using' directive</h2>
<p>For <code>.h</code> files it is strictly forbidden to use <code>using namespace OpenMS;</code>, <code>using namespace std;</code> or similar. This may cause name clashes (see 'Effective C++'). </p>
<p>In <code>.C</code> files you should not import complete namespaces to the scope either. Instead, introduce individual symbols to the scope where you need them. E.g. you would write <code>using std::vector;</code> instead of <code>using namespace std;</code>. This immediately gives a hint to where the symbol is defined as well.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">UInt is not Size!</h2>
<p>Whenever working with STL types (especially vectors), assign the return value of a <code>.size()</code> operation to the OpenMS type <code>Size</code>, which is defined as follows </p>
<div class="fragment"><div class="line"><span class="comment">// OpenMS/include/CONCEPT/Types.h</span></div>
<div class="line"><span class="keyword">typedef</span> <span class="keywordtype">size_t</span> <a class="code" href="group__Concept.html#gaf9ecec2d692138fab9167164a457cbd4">Size</a>;</div>
</div><!-- fragment --><p>The correct usage is: </p>
<div class="fragment"><div class="line">std::vector<String> myVec;</div>
<div class="line">myVec.push_back(<span class="stringliteral">"hello"</span>);</div>
<div class="line"><span class="keywordflow">for</span> (Size i=0; i<myVec.size(); ++i)</div>
<div class="line">{</div>
<div class="line"> std::cout << <span class="stringliteral">"Index: "</span> << i << <span class="stringliteral">" Value: "</span> << myVec[i] << std::endl;</div>
<div class="line">}</div>
</div><!-- fragment --><p>Particularly do <b>not</b> use UInt as substitute for Size! Even though UInt and Size are equivalent on prominent 32bit systems, they are usually different types on 64bit systems, where UInt is 32bit, whereas Size is 64bit depending on the platform. Using UInt leads to warnings (at best) and might even break your code! </p>
<p>Size is an unsigned type!If you need a signed type (e.g. when comparing length of vectors) use SignedSize (also defined in <a class="el" href="Types_8h.html">types.h</a>)<br/>
</p>
<p>Use SignedSize if you require loop variables with negative values: </p>
<div class="fragment"><div class="line">std::vector<String> myVec;</div>
<div class="line">myVec.push_back(<span class="stringliteral">"hello"</span>);</div>
<div class="line"><span class="keywordflow">for</span> (<a class="code" href="group__Concept.html#gae113cb41304c6692c7bf5d0624dc6f0f">SignedSize</a> i=0; i<(<a class="code" href="group__Concept.html#gae113cb41304c6692c7bf5d0624dc6f0f">SignedSize</a>)myVec.size() - 1; ++i)</div>
<div class="line"><span class="comment">// never use Size here, because if myVec.size()==0 then Size x = 0 - 1; gives some really BIG number!</span></div>
<div class="line">{</div>
<div class="line"> std::cout << <span class="stringliteral">"Index: "</span> << i << <span class="stringliteral">" Value: "</span> << myVec[i] << std::endl;</div>
<div class="line">}</div>
</div><!-- fragment --><h2 style="margin-top:20px; border-top:1px solid grey;">Math functions</h2>
<p>Using GCC a lot of common math functions are available (e.g. trunc(), <a class="el" href="group__MathFunctionsMisc.html#ga3994eea4342458b8d83ae1984b72d6ac" title="Rounds the value. ">round()</a>, log2(), isnan() or isinf() etc). However, this is <b>not</b> required by the C++Standard, so Microsoft decided not to include them. You will break the windows port of OpenMS if you use them!<br/>
You can rely on <code>ceil()</code> and <code>floor()</code> to exist everywhere (</p>
<pre class="fragment">#include cmath </pre><p>). If you are not sure whats available try <a href="http://www.cplusplus.com/">http://www.cplusplus.com/</a> or for VisualStudio specific problems: MSDN (<a href="http://msdn.microsoft.com/en-us/visualc/default.aspx">http://msdn.microsoft.com/en-us/visualc/default.aspx</a>).<br/>
</p>
<h3><a class="el" href="group__MathFunctionsMisc.html#ga3994eea4342458b8d83ae1984b72d6ac" title="Rounds the value. ">round()</a></h3>
<p>OpenMS provides a <code><a class="el" href="group__MathFunctionsMisc.html#ga3994eea4342458b8d83ae1984b72d6ac" title="Rounds the value. ">Math::round()</a></code> function for convenience (see <a class="el" href="MathFunctions_8h.html">MATH/MISC/MathFunctions.h</a>).</p>
<h3>isnan(), isinf()</h3>
<p>Use the boost library for those. You need to include</p>
<div class="fragment"><div class="line"><span class="preprocessor">#include <boost/math/special_functions/fpclassify.hpp></span> </div>
</div><!-- fragment --><p>Then use</p>
<p><code>boost::math::isinf(myNumber)</code> and <code>boost::math::isnan(myNumber)</code>.</p>
<h3>log()</h3>
<p>Windows does not support <code>log2()</code>, so use <code>log(x)/log(2)</code> instead.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Pass-by-value versus pass-by-reference</h2>
<p>Except of primitive types (int, double, float, ....) all method arguments should be passed as non-mutable references. </p>
<p>Return types of methods should be non-mutable references as well, where possible. Sometimes you cannot use references as the retuned value is constructed in the method. If the constructed type is large, you can save computation time like that:</p>
<div class="fragment"><div class="line"><span class="comment">//Bad idea</span></div>
<div class="line">LargeObject someFunction()</div>
<div class="line">{</div>
<div class="line"> LargeObject tmp = ...</div>
<div class="line"> <span class="keywordflow">return</span> tmp;</div>
<div class="line">}</div>
<div class="line"></div>
<div class="line"><span class="comment">//Better idea</span></div>
<div class="line"><span class="keywordtype">void</span> someFunction(LargeObject& obj)</div>
<div class="line">{</div>
<div class="line"> obj = ...</div>
<div class="line">}</div>
</div><!-- fragment --><h2 style="margin-top:20px; border-top:1px solid grey;">What does this OPENMS_DLLAPI in class headers do?!</h2>
<p>OPENMS_DLLAPI is a preprocessor macro and ensures that Visual Studio exports this class into the DLL when building the DLL or references the DLL when building an executable.</p>
<p>The OPENMS_DLLAPI macro is defined empty on other platforms, but it might still confuse the syntax parsing of your text editor or IDE. If you are using the Eclipse Platform, you can fix this at: Project->Properties->C/C++ Include Paths and Symbols.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">When do I use OPENMS_DLLAPI?!</h2>
<p>Whenever you've written a new OpenMS class, which is not a template class insert the macro into the header like this: </p>
<div class="fragment"><div class="line"><span class="keyword">class </span>Myclass</div>
<div class="line">{ ...</div>
</div><!-- fragment --><p> becomes </p>
<div class="fragment"><div class="line"><span class="keyword">class </span>OPENMS_DLLAPI Myclass</div>
<div class="line">{ ...</div>
</div><!-- fragment --><p>It is enough to prefix the class with the macro (do not prefix the members or member functions).</p>
<p>OPENMS_DLLAPI is also required for structs, global (including 'extern') variables and global functions, as long as they are not templates.<br/>
Never prefix templates with OPENMS_DLLAPI!<br/>
The only exeption to this rule is when a template is fully specialized (i.e. it can be instantiated). Additionally you need to prefix nested public structs/classes with OPENMS_DLLAPI, otherwise you cannot use them from outside the library.</p>
<p>A prominent global function is "operator <<", which is overloaded quite often for OpenMS classes. Unless it is templatized, prefix it with OPENMS_DLLAPI. If the operator is declared a friend of some class, also make sure the friend statement also contains the OPENMS_DLLAPI keyword. Otherwise you will get inconsistent DLL-linkage, e.g use: </p>
<div class="fragment"><div class="line"><span class="comment">// Adduct.h</span></div>
<div class="line"><span class="keyword">class </span>OPENMS_DLLAPI Adduct</div>
<div class="line">{ </div>
<div class="line"> ...</div>
<div class="line"> <span class="keyword">friend</span> OPENMS_DLLAPI std::ostream& <a class="code" href="namespaceOpenMS.html#a74df8b74439d1f76961c8d987fb074fd">operator << </a>(std::ostream& os, <span class="keyword">const</span> Adduct& a);</div>
<div class="line"> ...</div>
<div class="line">}</div>
<div class="line"></div>
<div class="line"><span class="comment">// Adduct.C</span></div>
<div class="line"><span class="keyword">namespace </span>OpenMS</div>
<div class="line">{</div>
<div class="line"> OPENMS_DLLAPI std::ostream& <a class="code" href="namespaceOpenMS.html#a74df8b74439d1f76961c8d987fb074fd">operator << </a>(std::ostream& os, <span class="keyword">const</span> Adduct& a)</div>
<div class="line"> {</div>
<div class="line"> ...</div>
<div class="line"> }</div>
<div class="line">}</div>
</div><!-- fragment --><p>If you forget the OPENMS_DLLAPI keyword, the DLL will have missing symbols and executables might not be able to link against it!</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Pointers versus references</h2>
<p>If you do not have really good reasons to do so, do not use pointers. They tend to cause segmentation faults! In 9 out of 10 cases a reference does the job as well!</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Iterators</h2>
<p>In simple looping constructs, iterators are generally preferable to indexed access. Prefer ``<code>++i</code>'' to ``<code>i++</code>'', because the preincrement operator can safe a copy constructor. Use <code>const_iterators</code> where possible to help avoiding unwanted side effects.</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Includes</h2>
<p>Includes in header files should be avoided and replaced by forward declarations.<br/>
Unnecessary includes cause longer compile times after changes in OpenMS header. </p>
<p>Reasons for includes in header files are: </p>
<ul>
<li>
Headers of base classes have to be included in the header of the derived classes. </li>
<li>
If a class has members of type T (not T* or T&) the header has to be included. </li>
<li>
Headers of template classes have to be included. </li>
</ul>
<p>An example class could look like this: </p>
<div class="fragment"><div class="line"><span class="preprocessor">#include <QtGui/QMainWindow></span></div>
<div class="line"><span class="preprocessor">#include <QtGui/QPainter></span></div>
<div class="line"></div>
<div class="line"><span class="comment">// Forward declaration in main namespace</span></div>
<div class="line"><span class="keyword">class </span>QLabel;</div>
<div class="line"></div>
<div class="line"><span class="keyword">namespace </span>OpenMS</div>
<div class="line">{</div>
<div class="line"> <span class="comment">// Forward declaration in OpenMS namespace</span></div>
<div class="line"> <span class="keyword">class </span>Spectrum1DWidget;</div>
<div class="line"></div>
<div class="line"> <span class="keyword">class </span>Dummy</div>
<div class="line"> : <span class="keyword">public</span> <a class="code" href="classQMainWindow.html">QMainWindow</a></div>
<div class="line"> {</div>
<div class="line"> ...</div>
<div class="line"></div>
<div class="line"> <span class="keyword">protected</span>:</div>
<div class="line"> Spectrum1DWidget* parent_;</div>
<div class="line"> QLabel* label_;</div>
<div class="line"> QPainter painter_;</div>
<div class="line"> }</div>
<div class="line">}</div>
</div><!-- fragment --><p><b>Note:</b> In OpenMS, Qt headers have to be included with the library prefix!</p>
<h2 style="margin-top:20px; border-top:1px solid grey;">Input/Output</h2>
<p>Note that code like <code>std::cout << "blabla" << std::endl;</code> forces the output buffer to be <em>flushed</em>, i.e. written to disk <em>immediately</em>, which is a big nuisance. Get used to write code like <code>std::cout << "blabla\n";</code>. Debug output can be an exception, because the content of the stream buffer may be lost upon segfault etc..</p>
<p>Write sufficiently many digits to avoid unnecessary rounding errors. Use the constants OpenMS::written_digits_real, OpenMS::written_digits_doublereal, etc. which are defined in <<a class="el" href="Types_8h.html">OpenMS/CONCEPT/Types.h</a>>. </p>
</div></div><!-- contents -->
<HR style="height:1px; border:none; border-top:1px solid #c0c0c0;">
<TABLE width="100%" border="0">
<TR>
<TD><font color="#c0c0c0">OpenMS / TOPP release 1.11.1</font></TD>
<TD align="right"><font color="#c0c0c0">Documentation generated on Thu Nov 14 2013 11:19:25 using doxygen 1.8.5</font></TD>
</TR>
</TABLE>
</BODY>
</HTML>
|