My coding style is largely based on the conventions documented by
Ellemtel Telecommunication Systems Laboratories in Programming in C++, Rules and
Recommendations, on the way the cc-mode
of GNU
Emacs works with its default settings, and on the warnings
generated by the GNU C++ Compiler, especially those that are enabled
with the -Weffc++ option.
This document mainly lists our deviations from the Ellemtel recommendations.
Include files have the file name extension ".h".
See also Ellemtel’s exception to the rule 1.
Implementation files in C++ have the file name extension ".C".
Implementation files in C have the file name extension ".c".
See also Ellemtel’s exception to the rule 2.
An include file may contain several class definitions, if the
classes are very closely related to each other. Subclass definitions
are an obvious example. Sometimes, when Standard Template Library
containers are used, a header file Name.h may
define both class Name and e.g. class
NameList that encapsulates std::list<class
Name>.
In order to reduce the number of files, there typically is at most one implementation file per class definition. There should not be any linking overhead, provided that the result is a monolithic program, not a library.
Only the function declarations are documented, in a JavaDoc style supported
by Doxygen.
Parameter names and their descriptions are separated by
TAB characters to save space in the source code.
The C-style comment separators /* and */
may be used as well. To exclude large blocks of the code during
testing and debugging, the preprocessor directives #if 0
and #endif can be used just like with C.
All type names are always prefixed with the appropriate keyword
enum, struct or class, unless
prohibited by the compiler. (Digital C++ Compiler does not allow
constructor calls to be prefixed with the keyword when the result is
an object, as in return class Example ();. When the
result is a pointer, there is no problem: return new class
Example ();.)
This rule helps the syntax highlighting rules of GNU Emacs and
avoids the need of partial declarations like class
Example;. When all object pointers and references are written
like class Example& instead of
Example&, there is no need to declare class
Example separately.
Include file names of system libraries, such as
<sys/types.h> or
<readline/readline.h>, can specify subdirectories
of the default include directories, as documented.
In an open-source project, there is less need to include version control system identifiers to the source files. Not including them avoids the need of recompiling when files are committed to the central repository.
Names of non-static member variables are prefixed with
my. Names of static member variables are prefixed with
the.
Static member variables are avoided by defining static methods that return references to objects having static linkage. Publicly accessible variables can be declared as static members for efficiency.
Alternatively, typedef names may be entirely in
lowercase and end in the suffix _t.
Lowercase characters shall not be used in preprocessor macro names
unless a library function is being renamed (#define bzero(s, n)
memset (s, 0, n)).
All inlined member functions are defined within the class definition to reduce the amount of code.
Always leave a space between a function name and an opening
parenthesis. This is compatible with the Emacs command
insert-parentheses. The only place where a space is not
allowed between the name and the left parenthesis is in a preprocessor
macro definition.
Braces ("{}") which enclose a block are to be placed
so that the opening brace is separated by a space from the preceding
symbol and the closing brace is on its own line in the same column as
the first symbol of the statement it terminates.
The style in which both braces are on their own lines would otherwise be acceptable, but the default behaviour of c++-mode is to apply the GNU indentation rules which would indent the statements contained in the braces twice:
while (expr)
stmt1 ();
// same level of indentation
while (expr) {
stmt1 ();
stmt2 ();
}
// two levels of indentation, NOT ACCEPTABLE
while (expr)
{
stmt1 ();
stmt2 ();
}
Tabulators (with tab stops every 8 characters) should be used
instead of ordinary spaces in formatting, when the code is indented by
several levels. This is the default GNU Emacs behaviour. The GNU
Emacs command tabify can be used to convert sequences of
spaces to tabulators.
When there are both const and non-const
access methods to member data, the non-const method may
return a non-const pointer or reference.
In the parser or in the lexical analyser, the added flexibility and efficiency of preprocessor macros is required. Not everything can be achieved with inline functions.
Since we use const to indicate the "ownership" of data
(when a method is passed a const pointer or reference to
an object, it is not responsible of deallocating the object), there
are situations where a const_cast is necessary.
When a switch statement has case labels
for all the values of an enumeration type, there must not be a
default branch. This allows the GNU C++ Compiler to warn
when the enumeration type is extended with new values but some of the
switch statements in the code are not updated
accordingly.
When allocating a large block of memory in a fail-safe algorithm,
calloc is safer than new, since it may
return a null pointer while new might throw an exception.