Clipper
|
This page discusses the conventions of coding style and memory management adopted in the Clipper libraries.
Clipper is written in C++, with extensive use of modern constructs such templates, and in particular the Standard Template Library (STL). The coding style of the library, and its API, both reflect this.
In particular, a developer writing code using Clipper objects should be able to do so with minimal or no use of pointers, or of the built-in new
and delete
operators. References are used in preference to pointers where possible. Heap objects, with the corresponding dangers of memory leakage, are avoided. (However, for the cases where the developer needs to use heap objects, an optional mechanism is provided for automatic garbage collection).
Clipper objects should generally be passed by reference rather than by value.
The package may be compiled to use either float
or double
for the representation of floating-point numbers. This is acheived by defining floating-point values with a user-defined type ftype
. This is set by a typedef
in lib/clipper_util.h.
Data may have a different type. Since data objects may be large, these may be individually typed to save memory or provide additional precision as required. Data types are based on templates in lib/clipper_datatypes.h.
The type for Fast-Fourier transforms is dependent on the FFTw library to which Clipper is linked. FFTw may be compiled for float
or double
.
Since crystallographic FFTs generally have quite short dimensions (< 1000), float
is recommended.
All Clipper objects belong to the Clipper
namespace, and can be accessed by using the Clipper:
: prefix or
using namespace Clipper;
Templates for reciprocal space datatypes are provided in the Clipper::datatypes
namespace. Instantiations of these types for float
and double
data are provided in Clipper::data32
and Clipper::data64
.
Classes are all named with an initial capital letter. Method names are all lowercase, with words separated by underscore ('_'). A handful of top level functions are implemented; these have an initial capital letter to distinguish them from standard library functions.
All Clipper objects are designed to be created on the stack. Such objects are destroyed automatically when they go out of scope. Large or variable-sized data items within an object are generally held in STL vectors, and so are stored on the heap, and automatically destroyed with the associated object.
Sometimes it may be useful to create Clipper container objects on the heap. In this case, the developer can arrange for the object to be destroyed when it is no-longer needed. However an alternative, automatic, method for memory management is provided, in the form of a destroyed_with_parent
flag. If in object is created on the heap (i.e. with new
), this flag may be set as follows:
Container* new_container = new Container( parent, "A container" ); new_container->set_destroyed_with_parent();
Then, as soon as parent
is destroyed, either by going out of scope, or by a delete
operator, the new container will also be destroyed.
Clipper objects should generally be passed by reference rather than by value. In particular passing a container type by value will lead to a container which is orphaned from the tree.
Passing or assigning an object always results in a 'deep copy', i.e. all of the data associated with the object is copied.
Code in the Clipper library should obey the following standards. Some of these are stylistic, but most are simply good practice. Code which does not obey these standards will be rejected from my tree.
There are a few places where I haven't yet finished implementing all of these standards, but I'm working on it.