Home  · Classes  · Annotated Classes  · Modules  · Members  · Namespaces  · Related Pages
C++ guide

This file contains general C++ guidelines that are not OpenMS-specific.

The 'using' directive

For .h files it is strictly forbidden to use using namespace OpenMS;, using namespace std; or similar. This may cause name clashes (see 'Effective C++').

In .C 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 using std::vector; instead of using namespace std;. This immediately gives a hint to where the symbol is defined as well.

UInt is not Size!

Whenever working with STL types (especially vectors), assign the return value of a .size() operation to the OpenMS type Size, which is defined as follows

// OpenMS/include/CONCEPT/Types.h
typedef size_t Size;

The correct usage is:

std::vector<String> myVec;
myVec.push_back("hello");
for (Size i=0; i<myVec.size(); ++i)
{
std::cout << "Index: " << i << " Value: " << myVec[i] << std::endl;
}

Particularly do not 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!

Size is an unsigned type!If you need a signed type (e.g. when comparing length of vectors) use SignedSize (also defined in types.h)

Use SignedSize if you require loop variables with negative values:

std::vector<String> myVec;
myVec.push_back("hello");
for (SignedSize i=0; i<(SignedSize)myVec.size() - 1; ++i)
// never use Size here, because if myVec.size()==0 then Size x = 0 - 1; gives some really BIG number!
{
std::cout << "Index: " << i << " Value: " << myVec[i] << std::endl;
}

Math functions

Using GCC a lot of common math functions are available (e.g. trunc(), round(), log2(), isnan() or isinf() etc). However, this is not required by the C++Standard, so Microsoft decided not to include them. You will break the windows port of OpenMS if you use them!
You can rely on ceil() and floor() to exist everywhere (

#include cmath 

). If you are not sure whats available try http://www.cplusplus.com/ or for VisualStudio specific problems: MSDN (http://msdn.microsoft.com/en-us/visualc/default.aspx).

round()

OpenMS provides a Math::round() function for convenience (see MATH/MISC/MathFunctions.h).

isnan(), isinf()

Use the boost library for those. You need to include

#include <boost/math/special_functions/fpclassify.hpp>

Then use

boost::math::isinf(myNumber) and boost::math::isnan(myNumber).

log()

Windows does not support log2(), so use log(x)/log(2) instead.

Pass-by-value versus pass-by-reference

Except of primitive types (int, double, float, ....) all method arguments should be passed as non-mutable references.

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:

//Bad idea
LargeObject someFunction()
{
LargeObject tmp = ...
return tmp;
}
//Better idea
void someFunction(LargeObject& obj)
{
obj = ...
}

What does this OPENMS_DLLAPI in class headers do?!

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.

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.

When do I use OPENMS_DLLAPI?!

Whenever you've written a new OpenMS class, which is not a template class insert the macro into the header like this:

class Myclass
{ ...

becomes

class OPENMS_DLLAPI Myclass
{ ...

It is enough to prefix the class with the macro (do not prefix the members or member functions).

OPENMS_DLLAPI is also required for structs, global (including 'extern') variables and global functions, as long as they are not templates.
Never prefix templates with OPENMS_DLLAPI!
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.

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:

// Adduct.h
class OPENMS_DLLAPI Adduct
{
...
friend OPENMS_DLLAPI std::ostream& operator << (std::ostream& os, const Adduct& a);
...
}
// Adduct.C
namespace OpenMS
{
OPENMS_DLLAPI std::ostream& operator << (std::ostream& os, const Adduct& a)
{
...
}
}

If you forget the OPENMS_DLLAPI keyword, the DLL will have missing symbols and executables might not be able to link against it!

Pointers versus references

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!

Iterators

In simple looping constructs, iterators are generally preferable to indexed access. Prefer ``++i'' to ``i++'', because the preincrement operator can safe a copy constructor. Use const_iterators where possible to help avoiding unwanted side effects.

Includes

Includes in header files should be avoided and replaced by forward declarations.
Unnecessary includes cause longer compile times after changes in OpenMS header.

Reasons for includes in header files are:

An example class could look like this:

#include <QtGui/QMainWindow>
#include <QtGui/QPainter>
// Forward declaration in main namespace
class QLabel;
namespace OpenMS
{
// Forward declaration in OpenMS namespace
class Spectrum1DWidget;
class Dummy
: public QMainWindow
{
...
protected:
Spectrum1DWidget* parent_;
QLabel* label_;
QPainter painter_;
}
}

Note: In OpenMS, Qt headers have to be included with the library prefix!

Input/Output

Note that code like std::cout << "blabla" << std::endl; forces the output buffer to be flushed, i.e. written to disk immediately, which is a big nuisance. Get used to write code like std::cout << "blabla\n";. Debug output can be an exception, because the content of the stream buffer may be lost upon segfault etc..

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 <OpenMS/CONCEPT/Types.h>.


OpenMS / TOPP release 1.11.1 Documentation generated on Mon Dec 23 2013 22:47:52 using doxygen 1.8.5