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.