First Page
News
Forum
In a Nutshell
About OGDF
FAQs
Key Features
Publications
Documentation
Overview Pages
How-Tos
Developer Resources
Reference Documentation
Get OGDF
Download
System Requirements
Installation (Linux/Mac)
Installation (Windows)
Projects
By OGDF Team
External
Team & Contact
Imprint
Finding bugs in code is a tedious but inevitable task in the software development process. Hence, it is very useful to put various tests into the code that check that functions are called correctly, that data structures remain consistent, and that invariants hold. Such tests automatically check for errors and guide the programmer to the real sources of errors. However, performing these tests is time-consumable and should be avoided in production code.
We maintain both debug and release code using conditional compilation. The debug version is indicated by the compiler define OGDF_DEBUG. Critical conditions can be certified using the assertion macro OGDF_ASSERT, e.g.,
template<class E> E &Array<E>::operator[](int i) { OGDF_ASSERT(m_low <= i && i <= m_high) return m_vpStart[i]; }
The condition is only checked during debugging. In a release build, the assertion macro expands to empty code and thus does not produce any performance loss. The following recommendations have to be observed:
int *pTable = new int[tableSize]; OREAS_ASSERT(pTable != 0)
is a programming error. According to the specification of the new operator, the return value may be 0 indicating that there is not enough memory available. If a function may return an error value, this value has to be checked and the calling function must handle the situation. In particular, not checking the return value of new or malloc() is a serious programming error!
Handling of error conditions is done using C++ exception handling. Objects that are thrown as exceptions belong to special exception classes defined in basic/exceptions.h . Exception classes have a common base class Exception, derived classes specialize the kind of exception to be thrown and allow discrimination of exceptions, e.g., InsufficientMemoryException indicates that memory could not be allocated, or AlgorithmFailureException indicates that an internal error in an algorithm has been detected.
It is important to take care that allocated resources will correctly be freed if an exception is thrown. Usually the best and easiest way is to use objects that allocate resources during construction and free them during deconstruction. This forwards the job of freeing allocated resources when an exception is thrown to the stack unwinding process, which is performed automatically when an exception is thrown. A more detailed treatment can be found, e.g., in Bjarne Stroustroup, The C++ Programming Language, third edition, Section 14.4, Resource Management.
There are a few more rules related to error handling:
exit() or abort() to terminate the application if an error occurs. If errors occur they have to be handled. Always bare in mind that your algorithms or functions are called from an application which keeps (usually unsaved!) important data. If you call exit() in your function, these data are lost and the application behaves in an intolerable manner to the user.The following rules have to be followed in order to prevent subtle and hard to find bugs.
const from a variable.Making code more readable improves its maintainability; the following recommendations help to achieve this goal:
// misleading: string2 looks like a string but is only a character! char* string1, string2;
NULL for a null-pointer (this is a relict from C), use 0 instead.if(p) write if(p != 0).The following guidelines deal with efficiency of code.
The following recommendations improve the usability, robustness, and maintainability of code.
