Commit d17c9f5e authored by scott snyder's avatar scott snyder
Browse files

- Allow omitting the =default= clause in a =switch= statement on an =enum=

   that handles all possible values.  Recent compilers will warn if some
   values are not handled, and it's better to get such a diagnosic
   at compile-time rather than at runtime.
 - Clarify avoid-typedef section.
 - Mention preference for =ATH_MSG_= macros.
 - Don't require =override= for destructors.
 - Avoid using =#pragma once=.
parent 83d0f5d6
#+MACRO: version 0.6
#+LaTeX_HEADER: \def\rulesversion{0.6}
#+MACRO: version 0.7
#+LaTeX_HEADER: \def\rulesversion{0.7}
#+TITLE: ATLAS C++ coding guidelines, version {{{version}}}
#+AUTHOR: Shaun Roe (CERN), Scott Snyder (BNL), and the former ATLAS Quality Control group
#+EMAIL: Correspondence to snyder@bnl.gov.
# Checked with org-mode 9.1.9 (as bundled with emacs 26.2)
# To export to PDF use `org-latex-export-to-pdf'.
# Along with the change to org-export-dictionary below, this changes
# the `Footnotes' section in HTML to `References'
......@@ -293,11 +294,24 @@ common or potential errors to avoid.
The include guard should include both the package name and class name,
to ensure that is unique.
Don't start the include guard name with an underscore!
Don't start the include guard name with an underscore; such names are
reserved to the compiler.
Be careful to use the same string in the =ifndef= and the =define=.
It's useful to get in the habit of using copy/paste here rather
than retyping the string.
Some compilers support an extension =#pragma once= that has similar
functionality. A long time ago, this was sometimes faster, as it allowed
the compiler to skip reading headers that have already been read.
However, modern compilers will automatically do this optimization
based on recognizing header guards. As =#pragma once= is nonstandard
and has no compelling advantage, it is best avoided.
In some rare cases, a file may be intended to be included multiple times,
and thus not have an include guard. Such files should be explicitly
commented as such, and should usually have an extension other than ``.h''.
commented as such, and should usually have an extension other than ``.h'';
``.def'' is sometimes used for thus purpose.
- *Use forward declaration instead of including a header file,
if this is sufficient.* [<<forward-declarations>>]
......@@ -467,40 +481,22 @@ for (std::vector<int>::const_iterator it = v.begin();
STL ranges are more simply written with a range-based for.
- *All switch statements must have a default clause.* [<<switch-default>>]
- *Switch statements should have a default clause.* [<<switch-default>>]
In some cases the default clause can never be reached because there
are case labels for all possible enum values in the switch statement,
but by having such an unreachable default clause you show a potential
reader that you know what you are doing.
A =switch= statement should have a =default= clause, rather than
just falling off the bottom, as a cue to the reader that this case
was expected.
You also provide for future changes. If an additional enum value is
added, the switch statement should not just silently ignore the new
value. Instead, it should in some way notify the programmer that the
switch statement must be changed; for example, you could throw an
exception
In some cases, a =switch= statement may be on a =enum= and includes
=case= clauses for all possible values of the =enum=. In such cases,
a =default= cause is not required. Recent compilers will generate
warnings if some elements of an =enum= are not handled in a =switch=.
This mitigates the risk that a =switch= does not get updated
after a new =enum= value is added.
- *Each clause of a switch statement must end with* =break=. [<<switch-break>>]
#+BEGIN_EXAMPLE
// somewhere specified: enum Colors { GREEN, RED }
// semaphore of type Colors
switch(semaphore) {
case GREEN:
// statement
break;
case RED:
// statement
break;
default:
// unforeseen color; it is a bug
// do some action to signal it
}
#+END_EXAMPLE
If you must ``fall through'' from one switch clause to another
(excluding the trivial case of a clause with no statements),
this must be explicitly stated in a comment. This should,
......@@ -1630,7 +1626,9 @@ private:
methods from the base class should also be declared with the =override= keyword.
If the signature of the method is changed in the base class, so that
the declaration in the derived class is no longer overriding it,
this will cause the compiler to flag an error.
this will cause the compiler to flag an error. (As an exception,
=override= is not required for destructors. Since there is only one
possible signature for a destructor, =override= doesn't add anything.)
#+BEGIN_EXAMPLE
class B
......@@ -2511,20 +2509,27 @@ some machines, left-to-right on others. -- end note ]
with typedefs are better handled by object oriented techniques, like
polymorphism.
A typedef statement, which is declared within a class as private or
protected, is used within a limited scope and is therefore acceptable.
Typedefs are acceptible where they provide part of the expected
interface for a class, for example =value_type=, etc.
in classes used with STL algorithms. They are often indispensible
in template programming and metaprogramming, and are also part
of how xAOD classes and POOL converters are typically defined.
Typedefs may be used to provide names expected by STL algorithms
(=value_type=, =const_iterator=, etc.) or to shorten cumbersome
STL container names.
In other contexts, they should be used with care, and should generally
be accompanied with a comment giving the rationale for the typedef.
Typedefs may also be used to identify particular uses of integral types.
Typedefs may be used as a ``customization point;'' that is, to allow
the possibility of changing a type in the future.
For example, the auxiliary store code uses integers to identify particular
auxiliary data items. But rather than declaring these as an integer type
directly, a typedef =auxid_t= is used. This makes explicit what variables
of that type are meant to be.
directly, a typedef =auxid_t= is used. This allows for the possibility
of changing the type in the future without having to make changes
throughout the code base. It also makes explicit that variables
of that type are meant to identify auxiliary data items,
rather than being random integers.
An exception to this are the =typedef= definitions used by the xAOD code.
A typedef may also be used inside a function body to shorten
a cumbersome type name; however, this should be used sparingly.
- *Code should use the standard ATLAS units for time, distance, energy, etc.* [<<atlas-units>>]
......@@ -2981,10 +2986,21 @@ The comment includes the fact that it is the perpendicular distance.
* Changes
** Version 0.7
- Allow omitting the =default= clause in a =swtich= statement on an =enum=
that handles all possible values. Recent compilers will warn if some
values are not handled, and it's better to get such a diagnosic
at compile-time rather than at runtime.
- Clarify avoid-typedef section.
- Mention preference for =ATH_MSG_= macros.
- Don't require =override= for destructors.
- Avoid using =#pragma once=.
** Version 0.6
- The =register= keyword is an error in C++17.
- Dynamic exception specifications are errors in C++17.
- Exceptions should be caught using const references, by value.
- Exceptions should be caught using const references, not by value.
- Discourage using protected data.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment