// This file describes the coding guidelines for c++. // It file is best viewed by browsing the doxygen-generated documentation. // It appears under the the "Related Pages" tab. // Consult the README file for instructions on generating the documentation. /*! \page CppCodingGuidelines C++ Coding Guidelines The following guidelines are based on a draft document from Baudouin Raoult, and were updated following the OOPS code review 11-15 July 2011. \section files_extensions Files Extensions - Each class is defined in two files: - The header file contains the class definition and has the extension .h. - The implementation file defines the methods and has the extension .cc - The file names should match the name of the class. - .cc and .h files must be in the same directory. \section header_files Header Files - Header files should follow the layout suggested in \link ExampleHeader Documents/ExampleHeader.h\endlink. - The public, protected and private sections of a class should be declared in that order (i.e. public first, private last). - Use \#include guards to protect against multiple inclusions. - The guard name should be constructed from the path to the .h file, as it appears in a \#include statement (see below), but with lowercase characters converted to uppercase, special characters replaced by underscores, and with a trailing underscore. - The \#endif for the guard should be followed on the same line by // and then the name of the guard. - All headers should be self-sufficient. A header should compile by itself. - There should be one main class per file. Helper classes are allowed, as long as they are only used from within the file. \section code_documentation Code Documentation - Documentation is generated using doxygen. - Instructions on building the documentation are in the \link README README\endlink file. - The doxygen manual can be found here. - See here for instructions on including \f$\mbox{\LaTeX}\f$ mathematical formulae. - Doxygen recognises special comments: - A brief comment is a single line like this: \verbatim /// This one-line comment gives a brief description of a class or method.\endverbatim - A detailed comment looks like this: \verbatim /*! * This is a detailed comment. It has more than one line, * and provides more complete information about a class or method. */ \endverbatim - Class definitions should be preceded by a doxygen brief comment followed by a detailed comment. - Method and member declarations should be preceded by a doxygen brief comment, unless the role of the method or member is completely obvious from its name. A detailed comment may also be provided. - Normal C++ comments should be used in .cc files where necessary to explain the internal logic of a function. - The code should be self-explanatory. But, add comments to explain complex algorithms. - Do not comment-out code. Use the source-code management system! - Don't include comments to indicate authorship or modification history. That is what git blame is for! - HTML links to auxiliary documents (e.g. pdf files) can be made to appear on the \link Overview Overview\endlink page by adding them to Documents/overview.h \section includes Includes - Do not include unnecessary headers. Use class forwarding. The compiler only needs to see a class definition when calling methods or establishing the size of an object. When referring to a pointer or a reference, the compiler does not need to know the detail of the class. - \#include\ instead of \#include\, if possible. - Included ".h" files must use the full path from the build directory ("oops") - Order of header files: - Own ".h" file. - C System headers (e.g. \). - C++ system headers (e.g. \). - Other library headers \). - Oops/util/logger project headers. - Within each of these categories,use alphabetical ordering. \section identifiers Identifiers - Identifiers should be in "camel case". That is, they should be mainly in lower case, with an upper case letter at the start of each internal word: e.g. changeResolution. - Do not use underscores to separate words. - Class names should start with an upper case letter. - Method and member names should start with a lower case letter. - Member names have an underscore at the end. - Use short identifiers for local variables, loop indices, etc. - Use longer, meaningful names for methods, members, classes, etc. \section use_of_const Use of Const - Use const wherever possible. - Avoid passing objects by const value. Pass by const reference instead. - Remember. The rule when reading definitions is to work from right to left. So, for example, char * const test means that test is a const pointer to a char object: - const char * test = "xyz"; // non-const pointer to const data - char * const test = "xyz"; // const pointer to non-const data - const char * const test = "xyz"; // const pointer to const data - bool isEmpty() const; // the isEmpty method does not change its object. \section classdesign How to Design Classes - By default make classes noncopyable (using boost::noncopyable), unless copy is needed - If you need copy, assignment or a destructor, then you probably need all three. - Make interfaces non-virtual. - Make virtual functions private. - Check for assignment to self in operator=. - A lot more guidelines needed here... \section interfaceprinciple Interface Principle - Guideline to be written... \section templates Templates versus Inheritance - Guideline to be written... \section inheritance Proper Inheritance - Remember the Liskov substitution principle: don't derive a "square" from a "rectangle"! - More guidelines required here... \section constructors_and_destructors Constructors and Destructors - Always declare copy and assignment constructors. Make them private unless you need to copy. - If the default copy constructor is sufficient, include a comment to this effect in the class definition. - Write the constructors and the destructors at the same time. - If the class has a virtual table, its destructor must be virtual. - All resources allocated by an object must be deallocated in the destructor. - Beware of partially constructed objects. - Except for the copy constructor, single-argument constructors should be declared explicit to prohibit implicit type conversions. - Base class destructors must be either public and virtual, or protected and not virtual. - The copy constructor should copy all the data. However, you may wish to give it a second, default argument to allow this behaviour to be over-ridden. - Do not code MyClass a = b; - This looks like assignment, but in fact calls the copy constructor. - Code MyClass a(b); instead. \section members Member Variables - Member variables should always be private. - Use accessors if you need to access a member variable from outside a class. - Don't use the accessors from within the class. Use the member itself. \section accessors Accessors - Accessors (a.k.a. getters and setters) should only be implemented if necessary. They break the encapsulation. - Accessors should be inline. - Accessors must have the same name as the member (but without the underscore) for example, the accessors for a member Foo foo_; should be: - const Foo& foo() const {return foo_; } - void foo(const Foo& f) { foo_ = f; } \section Methods - A method is a request to an object to do something or to provide something. The name of the method should reflect this. - E.g. changeResolution is preferable to resolutionChanger. - If a method is virtual in a base class, declare it as virtual in all derived classes that override it. \section opoverload Operator Overloading - Don't do it unless it is meaningful. - Don't subvert the mathematical properties (associativity, etc.). - Don't use an operator for conversion. Implement an "asDouble" method rather than "operator double()". \section pointers Pointers and References - Prefer references to pointers. If an object is guaranteed to exist, use a reference. - Passing or returning a non-const pointer means passing ownership of the pointed object. - Passing or returning a const pointer means keeping ownership of the pointed object, and that the pointed object can be null - In any other case, pass a reference to the object. Use const whenever the object will not be modified. \section static Use of Static - Avoid static if possible. - Be aware there are different types of static (function-local, file-scope). - Be aware that static variables cause problems in multi-threaded applications. \section useofcasts Use of Casts - Use c++ style casts. - Avoid downcasting. It is a symptom of bad inheritance, or not enough functionality in the base class - Write "double(expression)", not "(double) expression" - Guideline for the use of const cast to be written.... \section c_code C Code - Don't use C functions (e.g. printf) if C++ provides the same functionality. - If you must use a C function, prefix it with a double colon (e.g. "::sleep(10)") - When possible, wrap any C function in a C++ object (e.g. Sleeper) - Never use C style casts. - For unsigned value, use a typedef: typedef unsigned long ulong; \section preprocessor Preprocessor - The preprocessor should only be used to define \#include guards in .h files and for variables specified via the -D flag at compile time. - The preprocessor should not be used to define macros or constants. - The only permitted macros are ABORT, ASSERT and LOG, and macros defined in the boost library (e.g. BOOST_AUTO_TEST_CASE). - Don't pepper the code with ifdef's for machine/compiler dependent conditional compilation. Put any such code in a header file that can be included wherever needed. \section namespaces Namespaces - Model-independent code should be defined in the oops namespace. - Model-specific code should be defined in a separate, model-specific namespace. - Do not use an entire namespace (i.e. using directive). - By preference, use explicit namespace qualifications (e.g. std::string). However, using std::string etc. is acceptable. - using statements must never be used at global scope in a header file. - Use anonymous namespaces to restrict classes (e.g. Factories) to file scope. \section readability Readability - As far as possible, adhere to the rules listed in the Google C++ Style Guide. Note however that, contrary to the Google rules: - We do use streams. - We do (currently) use dynamic-casts - We allow non-const references as arguments. - Use cpplint to check your code. You may wish to turn off the following cpplint filters: - build/include_alpha (Because our idea of alphabetic order is different from Google's.) - build/include_order (Because cpplint wrongly thinks boost header files are c-system header files.) - readability/streams (Because we use streams.) - runtime/rtti (Because we use dynamic_casts.) - Keep lines below 80 characters. - Tab characters are not allowed. - Indent class and function bodies, if and for blocks, etc. - public, private and protected labels in a class definition should be indented one space with respect to the start of the class definition. - Use a two space indent for everything else. - It is preferable to indent code inside a namespace block. (However, we have many examples where this is not done.) - Split long lines in a way that makes it obvious that the code continues on the next line. - Continuation lines should be indented. - If you split an argument list, align the arguments with those on the previous line. - The opening brace should appear on the same line as the argument list, initialisation list, loop expression. etc. - The closing brace should appear on its own line, and aligned with the start of the statement it closes. - Braces should be used for all control structures (if, for, switch, etc.), even for "one-liners". - The else statement should be on the same line as the closing brace of the preceding block, and the opening brace of the following block. - Don't declare more than one member per line. - Don't initialise on the same line as you declare: (e.g. int i=3;). - Only one statement per line. - Remove whitespace at the end of a line. - Add a space after a comma in an argument list - All operators, except "!" should be surrounded by spaces. - Separate inline comments from code by at least two spaces - There should be a space after // (or after /// in the case of a Doxygen inline comment). - If the initialisation list in a class definition is too long to be on the same line, put in on the next line with the colon indented by 4 spaces. \section optimization Optimization - Pass objects by reference, not by value. - Prefer initialization over assignment. - Use ++i, not i++ when incrementing iterators. - Use the initialization list to initialize member objects. \section logging Logging - All logging messages should use the Logger class. Do not write to cout or cerr. - The logger adds a newline at the end of each message, so you don't need to. - endl forces an unnecessary buffer flush. Use \\n instead. - Use the appropriate logging category: - Info is for normal output - Trace is for more verbose output that could help the user understand the logical flow of the program. - Warning is for non-fatal error messages. - Error is for fatal error messages. - Configs is for echoing configuration data. - Debug is for debugging. Code in the shared repository should not output to this category. \section abort_and_assert ABORT, ASSERT and Error Handling - Errors should abort - Use the ABORT macro to exit after an error. Do not call exit directly. - Use the ASSERT macro liberally. It compiles to nothing unless the CHECK_ASSERTS macro variable is set, and it helps the reader to understand the code. - Remember, asserts can be disabled. Your code should not change behaviour if you disable the asserts. Use "if" and ABORT if you want something to be always checked. - Do not use exceptions (try/catch/throw) \section pointers Pointers and Smart Pointers - Use references instead of pointers as much as possible. - Use smart pointers in preference to c pointers. - Use boost::scoped_ptr if possible, otherwise boost::shared_ptr. - Do not use auto_ptr. \section retval Return Values - Use return values instead of argument where possible. - However, do not assume that the compiler will perform return value optimization. \section c_ftn_interface Interfacing Fortran and C++ - use ISO_C_BINDING - Only pass pointers and scalar variables between Fortran and C++ - naming convention (to be written...) - functions (to be written...) - parameters (to be written...) - const (to be written...) - order (input first, output last) (to be written...) - c prototype of Fortran function - generate automatically? to be written...) \section privpubprot Private, Public and Protected Access - Do not use "protected". - More rules please \section build Build - Tomas to write this! \section dirstruct Directory Structure - Code for each library should be in its own directory. - Add a rule on where to add a new model. */