1 Allowed language features
2 =========================
4 Most of these are not strict rules, but you should have a very good
5 reason for deviating from them.
7 Portability considerations
8 ^^^^^^^^^^^^^^^^^^^^^^^^^^
10 |Gromacs| uses C99 for C files and C++11 for C++ files.
11 C++ has a lot of features, but to keep the source code maintainable and easy to read,
12 we will avoid using some of them in |Gromacs| code. The basic principle is to keep things
13 as simple as possible.
14 For compatiblity, certain work-arounds are required because not all compilers support
15 these standards fully.
17 * MSVC supports only a subset of C99 and work-arounds are required in those cases.
18 * Before 7.0 (partial support in 6.5) CUDA didn't support C++11. Therefore any
19 header file which is needed (or likely will be nedded) by CUDA should not use C++11.
20 * We should be able to use virtually all C++ features outside of the header files
21 required by CUDA code (and OpenCL kernels), since we have gradually moved to
22 compilers that have full support for C++11.
27 |Gromacs| code must support the lowest common denominator of C++11 standard library
28 features available on supported platforms.
29 Some modern features are useful enough to warrant back-porting.
30 Consistent and forward-compatible headers are provided in ``src/gromacs/compat/``
31 as described in the `Library documentation <../doxygen/html-lib/group__group__compatibility.xhtml>`_
33 General considerations
34 ^^^^^^^^^^^^^^^^^^^^^^
35 As a baseline, |Gromacs| follows the C++ Core Guidelines |linkref1|, unless
36 our own more specific guidelines below say otherwise. We tend to be more restrictive
37 in some areas, both because we depend on the code compiling with a lot of different
38 C++ compilers, and because we want to increase readability. However, |Gromacs| is an
39 advanced projects in constant development, and as our needs evolve we will both
40 relax and tighten many of these points. Some of these changes happen naturally as
41 part of agreements in code review, while major parts where we don't agree should be
42 pushed to a redmine thread. Large changes should be suggested early in the development
43 cycle for each release so we avoid being hit by last-minute compiler bugs just before
46 * Use namespaces. Everything in ``libgromacs`` should be in a ``gmx``
47 namespace. Don't use using in headers except possibly for aliasing
48 some commonly-used names, and avoid file-level blanket ``using
49 namespace gmx`` and similar. If only a small number of ``gmx``
50 namespace symbols needed in a not-yet-updated file, consider
51 importing just those symbols. See also |linkref2|.
52 * Use STL, but do not use iostreams outside of the unit tests. iostreams can have
53 a negative impact on performance compared to other forms
54 of string streams, depending on the use case. Also, they don't always
55 play well with using C ``stdio`` routines at the same time, which
56 are used extensively in the current code. However, since Google tests
57 rely on iostreams, you should use it in the unit test code.
58 * Don't use non-const references as function parameters. They make it
59 impossible to tell whether a variable passed as a parameter may
60 change as a result of a function call without looking up the
62 * Use ``not_null<T>`` pointers wherever possible to convey the
63 semantics that a pointer to a valid is required, and a reference
64 is inappropriate. See also |linkrefnotnull|.
65 * Don't use C-style casts; use ``const_cast``, ``static_cast`` or
66 ``reinterpret_cast as appropriate``. See the point on RTTI for
67 ``dynamic_cast``. For emphasizing type (e.g. intentional integer division)
68 use constructor syntax. For creating real constants use the user-defined literal
69 _real (e.g. 2.5_real instead of static_cast<real>(2.5)).
70 * Avoid overloading functions unless all variants really do the same
71 thing, just with different types. Instead, consider making the
72 function names more descriptive.
73 * Avoid using default function arguments. They can lead to the code
74 being less readable than without (see |linkref3|). If you think that your specific
75 case improves readability (see |linkref4|), you can justify their use.
76 * Don't overload operators before thorough consideration whether it
77 really is the best thing to do. Never overload ``&&``, ``||``, or
78 the comma operator, because it's impossible to keep their original
79 behavior with respect to evaluation order.
80 * Try to avoid complex templates, complex template specialization or
81 techniques like SFINAE as much as possible. If nothing else, they
82 can make the code more difficult to understand.
83 * Don't use multiple inheritance. Inheriting from multiple pure
84 interfaces is OK, as long as at most one base class (which should be
85 the first base class) has any code. Please also refer to the
86 explanation |linkref5| and |linkref6|.
87 * Don't write excessively deep inheritance graphs. Try to not inherit
88 implementation just to save a bit of coding; follow the principle
89 "inherit to be reused, not to reuse." Also, you should not
90 mix implementation and interface inheritance. For explanation please
92 * Don't include unnecessary headers.
93 * Make liberal use of assertions to help document your intentions (but
94 prefer to write the code such that no assertion is necessary).
95 * Prefer ``GMX_ASSERT()`` and ``GMX_RELEASE_ASSERT()`` to naked
96 ``assert()`` because the former permit you to add descriptive text.
97 * Use gmx::Mutex rather than pthreads, std or raw thread-MPI mutexes.
98 * Use proper enums for variable whose type can only contain one of a
99 limited set of values. C++ is much better than C in catching errors
100 in such code. Ideally, all enums should be typed enums, please
102 * When writing a new class, think whether it will be necessary to make
103 copies of that class. If not, declare the copy constructor and the
104 assignment operator as private and don't define them, making any
105 attempt to copy objects of that class fail. If you allow copies,
106 either provide the copy constructor and the assignment operator, or
107 write a clear comment that the compiler-generated ones will do (and
108 make sure that they do what you
109 want). ``src/gromacs/utility/classhelpers.h`` has some convenience
110 macros for doing this well.
111 Starting from c++11, you can also use deleted functions in this case.
112 * Declare all constructors with one parameter as explicit unless you
113 really know what you are doing. Otherwise, they can be used for
114 implicit type conversions, which can make the code difficult to
115 understand, or even hide bugs that would be otherwise reported by
116 the compiler. For the same reason, don't declare operators for
117 converting your classes to other types without thorough
118 consideration. For an explanation, please see |linkref9|.
119 * Write const-correct code (no ``const_cast`` unless absolutely
121 * Avoid using RTTI (run-time type information, in practice
122 ``dynamic_cast`` and ``typeid``) unless you really need it. The cost
123 of RTTI is very high, both in binary size (which you always
124 pay if you compile with it) and in execution time (which you pay
125 only if you use it). If your problem seems to require RTTI, think
126 about whether there would be an alternative design that
127 wouldn't. Such alternative designs are often better.
128 * Don't depend on compiler metadata propagation. struct elements
129 and captured lambda parameters tend to have ``restrict`` and
130 alignment qualifiers discarded by compilers, so when you later
131 define an instance of that structure or allocate memory to
132 hold it, the data member might not be aligned at all.
133 * Plan for code that runs in compute-sensitive kernels to have useful
134 data layout for re-use, alignment for SIMD memory operations
135 * Recognize that some parts of the code have different requirements -
136 compute kernels, mdrun setup code, high-level MD-loop code,
137 simulation setup tools, and analysis tools have different needs, and
138 the trade-off point between correctness vs reviewer time vs
139 developer time vs compile time vs run time will differ.
142 .. |linkref1| replace:: `c++ guidelines <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines>`__
143 .. |linkref2| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#sf7-dont-write-using-namespace-in-a-header-file>`__
144 .. |linkref3| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#i23-keep-the-number-of-function-arguments-low>`__
145 .. |linkref4| replace:: `here <https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#f51-where-there-is-a-choice-prefer-default-arguments-over-overloading>`__
146 .. |linkref5| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c135-use-multiple-inheritance-to-represent-multiple-distinct-interfaces>`__
147 .. |linkref6| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c136-use-multiple-inheritance-to-represent-the-union-of-implementation-attributes>`__
148 .. |linkref7| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c129-when-designing-a-class-hierarchy-distinguish-between-implementation-inheritance-and-interface-inheritance>`__
149 .. |linkref8| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-class>`__
150 .. |linkref9| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-explicit>`__
151 .. |linkrefnotnull| replace:: `here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ri-nullptr> and here <http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-nullptr>`__
153 .. _implementing exceptions:
155 Implementing exceptions for error handling
156 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
157 See :ref:`error handling` for the approach to handling run-time
158 errors, ie. use exceptions.
160 * Write exception-safe code. All new code has to offer at least the
161 basic or nothrow guarantee to make this feasible.
162 * Use std (or custom) containers wherever possible.
163 * Use smart pointers for memory management. By default, use
164 ``std::unique_ptr`` and ``gmx::unique_cptr`` in assocation with any
165 necessary raw ``new`` or ``snew`` calls. ``std::shared_ptr`` can be
166 used wherever responsibility for lifetime must be shared.
167 Never use ``malloc``.
168 * Use RAII for managing resources (memory, mutexes, file handles, ...).
169 * It is preferable to avoid calling a function which might throw an
170 exception from a legacy function which is not exception safe. However,
171 we make the practical exception to permit the use of features such
172 as ``std::vector`` and ``std::string`` that could throw
173 ``std::bad_alloc`` when out of memory. In particular, |Gromacs| has
174 a lot of old C-style memory handling that checking tools continue
175 to issue valid warnings about as the tools acquire more
176 functionality, and fixing these with old constructs is an
177 inefficient use of developer time.
178 * Functions / methods should be commented whether they are exception
179 safe, whether they might throw an exception (even indirectly), and
180 if so, which exception(s) they might throw.
182 Preprocessor considerations
183 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
184 * Don't use preprocessor defines for things other than directly
185 related to configuring the build. Use templates or inline functions
186 to generate code, and enums or const variables for constants.
187 * Preprocessing variables used for configuring the build should be
188 organized so that a valid value is always defined, i.e. we never
189 test whether one of our preprocessor variables is defined, rather we
190 test what value it has. This is much more robust under maintance,
191 because a compiler can tell you that the variable is undefined.
192 * Avoid code with lengthy segments whose compilation depends on #if
194 * Prefer to organize the definition of a const variable at the top of
195 the source code file, and use that in the code. This helps keep all
196 compilation paths built in all configurations, which reduces the
197 incidence of silent bugs.
198 * Indent nested preprocessor conditions if nesting is necessary and
199 the result looks clearer than without indenting.
200 * Please strongly consider a comment repeating the preprocessor condition at the end
201 of the region, if a lengthy region is neccessary and benefits from
202 that. For long regions this greatly helps in understanding
203 and debugging the code.