CppCodingStandards
C++ Coding Standards
Note that coding standards and guidelines will never be perfect and that not everyone will agree with every guideline or naming convention. The purpose of the guidelines and standards are to maintain consistency in the source code.
<<TableOfContents()>>
Header Files
Keep #include directives to a minimum in header files. Prefer forward declaring classes/structs if at all possible.
Don't use an #include when a forward declaration would suffice.
While includes should be kept to a minimum, if something is used in a file and cannot be forward declared, it should be explicitly included. This is especially relevant for things such as std::string which might be sucked in from another source. (There is a cpplint.py check for this)
All files, headers and implementation, should include everything they need to be self-sufficient. They should never assume something will be pre-included.
All implementation files (.cc) should include `config.h` & relevant header files, that are referenced by the implementation file.
For #include'ing header files that are in a local directory, use this form:
#!highlight cpp #include "kernel/communication/Client.h"
For #include'ing system headers or library header files, use the form:
#!highlight cpp #include <somelib/some_lib_header.h>
Do not make header files that consist only of other header files.
Use C++ includes, not C includes
Use C++ includes, not C ones. For instance, you should use:
#!highlight cpp #include <cstdio> #include <cstring>
and not:
#!highlight cpp #include <stdio.h> #include <string.h>
Include Guards
All headers must use include guards. The name of the include guard #define should be the file path from the source root, in all uppercase, with underscore separation.
For instance, if you are editing the file `/kernel/communication/Client.h`, you would use the following:
#!highlight cpp #ifndef KERNEL_COMMUNICATION_CLIENT_H #define KERNEL_COMMUNICATION_CLIENT_H ... #endif /* KERNEL_COMMUNICATION_CLIENT_H */
Please always place a comment on the #endif indicating the include guard #define's label
Never Use `using namespace` in Header Files
You should never use a `using namespace` directive in a header file.
Always specify namespace prefixes in header files, even for std:: symbols.
Correct:
#!highlight cpp // /kernel/communication/Packet.h #include <vector> namespace kernel { namespace communication { class Packet { public: Packet(); /** Get internal buffer */ std::vector<uint8_t> &buffer(); private: std::vector<uint8_t> _buffer; }; } // namespace communication } // namespace kernel
Incorrect:
#!highlight cpp // /kernel/communication/Packet.h #include <vector> using namespace std; namespace kernel { namespace communication { class Packet { public: Packet(); /** Get internal buffer */ vector<uint8_t> &buffer(); private: vector<uint8_t> _buffer; }; } // namespace communication } // namespace kernel
Even better, see the section on typedef'ing :)
Variable Declaration and Naming Standards
Variable Declaration Order
Always think about and read declarations right to left.
If something is a reference or pointer to non-modifiable data, you should structure the declaration like so:
type [data-const-modifier] [pointer-or-reference] [pointer-const-modifier] symbol-name
For example:
#!highlight cpp std::string my_data; // a string called my_data char const *ptr= my_data.c_str(); // a pointer to unmodifiable char array named ptr char const * const c_ptr= my_data.c_str(); // a non-modifiable pointer to // non-modifiable char array named c_ptr // a function accepting a reference to a non-modifiable string object void fun(std::string const &str) { ... }
Namespace Names
Namespaces should be all lowercased, with preference to single words. If a namespace must be dual-worded, use underscores.
Acceptable examples:
- kernel
- kernel::client
- kernel::client::communication
Class Names
Class names should be PascalCased and should adequately describe the object, with as little abbreviation as possible. Where necessary, acronym'd parts of a class name should be kept in all uppercase.
Prefixing (such as prefixing all classes with Cls) is to be avoided.
For abstract base classes, it is encouraged to name the class with an adjective that illustrates the interface's main purpose. For instance, an abstract base/interface class that describes a class type that can be interrupted by a signal could be called "Interruptible"
Acceptable examples:
#!highlight cpp class SQLClient; // describes an object acting as a client to a SQL store class Interruptible; // an interface class describing a type of object that can be interrupted by some signal
Poor examples:
#!highlight cpp class ClsClient; // Don't use useless prefixes! class Tool; // Doesn't describe anything. A tool which does '''''what'''''?
Class Member Variable Names
Note: Please see Scoping for reasons why all member data should be private.
Private Class Member Data
Private member data variables should be prefixed with an underscore and should be all lowercase with underscore separation.
Example:
#!highlight cpp class Student { public: Student(std::string const &name, uint64_t id) : _name(name), _id(id) {} ~Student() {} private: std::string _name; ///< The student's name uint64_t _id; ///< The student's identifer }
Class Method Names
Class methods should be lowercased, with underscore separation. Of utmost importance is the fact that the method name should indicate an *action* that describes the *action* that is performed by the method.
Standardized Accessor and Mutator Method Pairing
Use the following naming convention for public accessor/mutator pairs for private member data:
Accessors:
For const returns, name the accessor the same as the private member data variable, without the underscore prefix
For accessing pointers to mutable composite data, use the prefix of "mutable_" along with the composite member data variable name
For regular, non-pointer setters, prefix the name of the private member data with "set_".
For aggregate composition of member data (when member data is of a container type), provide appropriately-indexed accessors that match the contained composite data type. For instance, if a class has a private member:
#!highlight cpp std::vector<Teacher *> _teachers;
You should provide accessor methods to the Teacher pointer members
like so:
#!highlight cpp Teacher *teacher(size_t index);
For adding elements to such composite members, prefix adder methods
with "add_" like so:
#!highlight cpp void add_teacher(Teacher *new_teacher);
Continuing the example from the previous section:
#!highlight cpp class Teacher { public: Teacher(std::string const &name) : _name(name) {} ~Teacher() {} private: std::string _name; ///< The teacher's name }; class Student { public: Student(std::string const &name, uint64_t id) : _name(name), _id(id) {} ~Student() {} /** * Returns the student's name */ std::string const &name() const { return _name; } /** * Returns the student's id */ uint64_t id() const { return id; } /** * Returns a pointer to the student's homeroom * teacher or NULL if not set */ Teacher const &homeroom_teacher() const { return *_homeroom_teacher; } /** * Returns a reference to a container of * all the student's teachers */ std::vector<Teacher *> &teachers() const { return _teachers; } /** * Returns a specific teacher at a supplied * index */ Teacher const &teacher(size_t index) const { // note: NOT exception safe! Just an example! return *(_teachers[index]); } /** * Returns a pointer to the student's * homeroom teacher */ void set_homeroom_teacher(Teacher *teacher) { _homeroom_teacher = teacher; } /** * Adds a new teacher to the container * of teachers for this student. */ void add_teacher(Teacher *teacher) { _teachers.push_back(teacher); } private: std::string _name; ///< The student's name uint64_t _id; ///< The student's identifer Teacher *_homeroom_teacher; ///< The student's homeroom teacher std::vector<Teacher *> _teachers; ///< All of the student's teachers } ==== Private Pure Virtual Implementation Method Names ==== If a public interface requires virtualization be implemented via private, pure- virtual methods, one should name the pure virtual implementation method the same as the public method, prefixed with "do_" For instance: {{{#!highlight cpp class Engine { public: Engine() : start_time(0) {} virtual ~Engine() {} int start(); private: virtual int do_start() = 0; time_t start_time; }; class V6Engine :public Engine { public: V6Engine() : Engine() {} ~V6Engine() {} private: int do_start(); }; int Engine::start() { // log the time the engine started start_time = time(NULL); // call subclass' private implementation return do_start_time(); } int V6Engine::do_start() { // start the engine and return the // results of starting the engine... }
Enums
The names of enums should be lowercase and end with a "_t" suffix to designate they are a type.
Example:
#!highlight cpp enum option_t { DEFAULT = 0, // the default option MINIMUM = 1, // the minimum option MAXIMUM = 2 // the maximum option }; option_t my_option = DEFAULT;
Boolean Variables
Boolean variables should have a prefix which indicates their "booleanness" and should be a verb.
For example, if you have a variable that describes whether something is valid, use:
<source> bool is_valid; bool has_drivers; bool can_be_empty; </nowiki></pre>
and not:
<source> bool valid; bool drivers; bool emptiness; </nowiki></pre>
Module/Global Variable Names
Variables that exist at the global scope should generally be discouraged, however the naming of such module-level or global variables should be lowercased, with underscore separation.
Example:
uint32_t my_global_option;
Note:
Constants are not variables and follow a separate naming convention
Constant Names
The names of constants should be in all uppercase, regardless of the constant's scope.
There should be no prefixing of constants with unnecessary type information.
Acceptable examples:
#!highlight cpp std::string const DEFAULT_DATA_DIRECTORY = "/var"; class Client { public: uint32_t const DEFAULT_PORT = 9999; };
Incorrect examples:
#!highlight cpp std::string const STR_DEFAULT_DATA_DIRECTORY = "/var"; // Uses unnecessary prefix std::string const default_data_directory = "/var"; // Does not use all uppercase
Source Filenames and Directory Structure
Directories should match the namespaces that compose the program.
Headers should end with ".h" and source files should end with ".cc"
Source files and headers should be named the same as the class and namespace that is contained in the file.
Example:
Assume that you are coding a class named Client that exists in the
- kernel::communication namespace.
The header and source files respectively should be:
/kernel/communication/Client.h /kernel/communication/Client.cc
Indentation and Formatting
Indentation
TAB characters should be eliminated from all source files.
For Vi(m) users, use the expandtab option
Indentation should be 2 spaces exactly at all indentation levels
Every block of code except namespaces and scope-specifiers should be indented a single level. namespace { } blocks and scope-specifiers such as private: should not be indented.
switch statements should indent case labels one indentation level.
Example:
#!highlight cpp namespace kernel { namespace communication { enum option_t { OPTION_ONE = 1, OPTION_TWO = 2 }; bool some_boolean_variable = false; option_t some_option = OPTION_TWO; class Client { public: Client() { if (not some_boolean_variable) { switch (some_option) { case OPTION_ONE: { // do option one } default: { // do default action } } } } } } // namespace communication } // namespace kernel
Spacing
Variable Declarations
Use a single space between the variable's type and the variable's label (name).
Do not align variable labels on indentation levels as this indentation invariably gets out-of-line as the code is modified.
Correct:
#!highlight cpp bool is_derived; uint64_t num_derivatives;
Incorrect:
#!highlight cpp bool is_derived; // There should not be more than one space between type and label uint64_t num_sizes; // Do not align variable labels on bool has_size; // indentation levels
Pointer and Reference Variables
When declaring a pointer variable or argument, place the asterisk adjacent to the variable name. For instance:
#!highlight cpp string *foo;
Use `NULL` when referring to the null pointer, not `0`.
When declaring a reference variable or argument, place the ampersand adjacent to the variable name. For instance:
#!highlight cpp string &foo;
Assignment Operators
One space before and one space after assignment operators.
Do not align assignment variables on indentation levels, since such indentation inevitably gets out-of-line as the code is modified.
Correct:
bool my_bool = false; uint32_t my_int = 0;
my_int += 1;
Incorrect:
bool my_bool= false; // There should be one space before assignment operator
uint32_t num_sizes = 0; // Do not align assignments on an uint64_t num_red_sizes= 0; // indentation level/tab line
Comparison Operators
When testing for comparisons, be as descriptive and verbose as possible, and use a space between the negation operator.
For instance, prefer this:
#!highlight cpp if (can_print == false) {...};
or this:
#!highlight cpp if (not can_print) {...}
to this:
#!highlight cpp if (!can_print) {..};
Design Guidelines
Keep Methods/Functions Short
Long functions are sometimes appropriate, so no hard limit is placed on functions length. If a function exceeds about 40 lines, think about whether it can be broken up without harming the structure of the program.
Even if your long function works perfectly now, someone modifying it in a few months may add new behavior. This could result in bugs that are hard to find. Keeping your functions short and simple makes it easier for other people to read and modify your code.
You could find long and complicated functions when working with some code. Do not be intimidated by modifying existing code: if working with such a function proves to be difficult, you find that errors are hard to debug, or you want to use a piece of it in several different contexts, consider breaking up the function into smaller and more manageable pieces.
In summary, prefer functions that are small and focused.
Avoid Global Static Class Instances
Avoid global static class instances because of initialization order ambivalence. If you need a singleton object, use a public static class method named singleton() that initializes a method-scoped static object and returns that object. Ensure the singleton class' constructor is private to avoid any other way of creating the object.
Example:
#!highlight cpp class MySingleton { public: MySingleton &singleton() { static MySingleton my_object; return my_object; } private: MySingleton(); };
Liberal Use of `typedef`
For readability, make liberal use of `typedef`, especially in the case of STL container types inside classes.
For instance, let's assume this code:
#!highlight cpp class Teacher; class Student { public: std::vector<Teacher *> &teachers(); private: std::vector<Teacher *> _teachers; };
The above code is more readable and maintainable when a `typedef` is used
for the `std::vector<Teacher *>` as shown below:
#!highlight cpp class Teacher; class Student { public: typedef std::vector<Teacher *> Teachers; Teachers &teachers(); private: Teachers _teachers; };
The `typedef` makes it easier to read and makes future possible modifications
to what is a collection of Teachers easier (for instance, changing `std::vector<>`
to `std::list<>`)
Class Design
Some helpful suggestions and best practices from Scott Meyers, Herb Sutter, and Andrei Alexandrescu:
- Make interfaces easy to use correctly and hard to use incorrectly
- Treat class design as type design
- Prefer pass-by-reference-to-const to pass-by-value
- Don't try to return a reference when you must return an object
- Declare data members private
except in behaviourless aggregates (C-style structs)
- Prefer non-member non-friend functions to member functions
- Declare non-member functions when type conversion should apply to all parameters
- Consider support for a non-throwing swap
- Be clear what kind of class you're writing
- Prefer minimal classes to monolithic classes
- Prefer composition to inheritance
- Avoid inheriting from classes that were not designed to be base classes
- Prefer providing abstract interfaces
- Public inheritance models "is a"
- Private inheritance models "is implemented in terms of"
- Public inheritance is substitutability. Inherit, not to reuse, but to be reused
- Practive safe overriding
- Consider making virtual functions nonpublic, and public functions nonvirtual
- Avoid providing implicit conversions
- Don't give away your internals
- Pimpl judiciously
- Always provide new and delete together
- If you provide any class-specific new,
provide all of the standard forms (plain, in-place, and nothrow)
Always Use RIIA And Understand Who Owns What Memory/Resources
Never use malloc and free. Use C++'s new operator coupled with smart pointer containers.
When calling new, place the returned pointer to a resource into either a boost::shared_ptr<> or a boost::scoped_ptr<>. Doing so ensures that resources will be properly freed and that you do not need to call delete yourself.
Always put shared_ptr<> object construction on a separate code line to avoid problems with unnamed temporaries.
Example:
#!highlight cpp // Example of scoped_ptr<> usage for a new'd object // that should always be deleted at the end of a function #include <boost/scoped_ptr.hpp> class MyClass { public: MyClass() {} ~MyClass() {] void do_something() { cout << "did something" << endl; } }; void example_scoped() { boost::shared_ptr<MyClass> my_object(new MyClass()); my_object.do_something(); SomeClass *my_ptr_to_object= my_object.get(); my_ptr_to_object->do_something(); }
For objects that are shared by multiple threads of execution or different
owners, use boost::shared_ptr<>.
Implement the Pimpl idiom using `boost::shared_ptr<>`
For more information on smart pointers, see this reference
Make Things As Const as Possible
Make methods that do not modify underlying member data const as much as possible.
Move Inline Method Bodies Out of Class Definitions
Instead of inlining method bodies in a class definition, instead declare the method regularly and define it in the header file below the class definition with an inline specifier.
Example:
#!highlight cpp class Foo { public: void bar(); }; inline void Foo::bar() { /* do something */ }
Use Initializer Lists Properly!
Initialize member data using initializer lists, instead of using assignment of member data in a constructor's body.
Correct:
#!highlight cpp class MyClass { public: MyClass(uint32_t number_1, uint32_t number_2) : _number_1(number_1), _number_2(number_2) {} private: uint32_t _number_1; uint32_t _number_2; };
Incorrect:
#!highlight cpp class MyClass { public: MyClass(uint32_t number_1, uint32_t number_2) { _number_1 = number_1; _number_2 = number_2; } private: uint32_t _number_1; uint32_t _number_2; };
Declaration Order
Your class definition should start with its public: section, followed by its protected: section and then its private: section. If any of these sections are empty, omit them.
Reuse of Open Source Libraries
When presented with a choice between writing your own code and re-using an open source library that already does what you want to do, in general you should re-use the open source library.
Libraries you should use whenever possible:
Boost C++ libraries and components:
boost::program_options boost::any boost::thread boost::regex boost::asio boost::smart_ptr
Google Protobuffers gettext C++0x and the STL C++0x atomic<>
Using Namespaces Properly
Code that lives inside a specific module or category should reside inside a namespace indicating the module's functionality. In both header and source files for such code, the code should be encapsulated inside namespace { } blocks.
Example:
#!highlight cpp // Header file /kernel/communication/Client.h namespace kernel { namespace communication { class Client { ... }; } // namespace communication } // namespace kernel // Source file /kernel/communication/Client.cc
NEVER place include statements inside of a namespace block.
Exception Handling
Use exceptions freely, but wisely. Exceptions should be reserved for catching exceptional behaviour, not naturally-occurring or expected errors.
Make try ... catch blocks as small in scope as possible.
Error Return/Retrieval
Do not return integer error or success codes.
Instead, use an enum that adequately describes the error/success returns and helps to clearly document the code.
Do NOT use #defines. Use an enum. After all, we're coding in C++, not C. :)
Example:
#!highlight cpp enum return_t { SUCCESS = 0, ERROR_IO = 1, // Error occurred doing I/O ERROR_LOGIC = 2, // There was a logical error... };
Consider also using boost::system::error_code
objects for common error returns from system calls.
Make Liberal Use of `assert`s
Make liberal use of asserts in your code.
However, be sure not to have any side-effects in your assert()s!
For instance, the following contrived example has a problematic side effect:
#!highlight cpp void some_function() { size_t x, y; for (x = 0, y = 0; x < 10; ++x) { assert((y = (x + (y - 1))) > x); cout << y; } }
The side-effect is that the y variable is being assigned
to in the assert() statement. Depending on whether asserts are compiled
out of the source code, the output of the function is different.
Use C++-style Casts
Avoid using C-style casts. Use C++-style casts instead, which are more explicit and sometimes safer to use.
Example:
#!highlight cpp // cast between integer types uint32_t my_number = 100; int32_t my_signed_number = static_cast<int32_t>(my_number);
Namespacing
All code should be namespaced properly into namespaces representing the directory structure in which the classes/functions reside.
For instance, if a source file `/kernel/client/Client.h` exists, containing a class "Client", the namespacing should be:
namespace kernel { namespace client { class Client { ... }; } // namespace client } // namespace kernel
Types
Use standard integer and limit types defined in <cstdint> and <climit>
Prefer explicitly sized integer types, such as int64_t, over non-explicitly-sized integer types, such as long.
Use size_t when you need an unsigned integer type designating size, length, or capacity.
Use ssize_t when you need a signed integer type designating a return from a read() or write() call that may return a value less than 0 in case of an error.
When you need a size type that is platform-specific, use size_t and ssize_t.
Use off_t for file positions/offsets.
Use ptrdiff_t for integers representing offset or difference between pointers.
Code Documentation and Commenting
Comment Style
We will be using Doxygen to generate on-line source code documentation. Doxygen is very versatile and supports several different styles of commenting. In order to have some consistency in the code, below is the recommended commenting style.
Preceed Doxygen commands with the at-sign (@) instead of the backslash (\). E.g.:
#!highlight cpp @brief @details
Use the Javadoc style of commenting for multi-line comment blocks. For example:
#!highlight cpp /** * ...text... */
Note: The JAVADOC_AUTOBRIEF Doxygen option will be used.
File Comments
Documenting a source file is recommended, but is absolutely necessary if you want to document a global object (function, typedef, enum, macro, etc.). Otherwise, the documentation for the global object will not be generated.
A file should be commented at the beginning of the file.
Example:
#!highlight cpp /** * @file * example.h * * @brief * An example header file. * * @details * A more detailed description here. */
Class Comments
All classes should be commented immediately preceeding the class definition in the header file.
Class Methods
The methods of the class should be commented within the header file, not the implementation file. The API of the class should be clearly exposed through the header file only. Describe what the method does, what its parameters are, and what it returns. If there are complex details about the implementation that you feel need documenting, do so inside the method in the implementation file.
Also see comments in the #Function and Method Comments section.
Class Member Variables
Member variables should be commented in the header, when appropriate. Members can be commented either above the variable declaration:
#!highlight cpp /** * Brief description of myVar. * More detailed description of myVar that works because of JAVADOC_AUTOBRIEF. */ int myVar;
Or, the member variables may be commented on the same line as the variable
declaration:
#!highlight cpp int myVar; ///< A brief description of myVar int myVar2; ///< This is a detailed description of myVar2 because it ///< spans multiple lines.
Class Example
#!highlight cpp /** * @brief * A brief description of HolyHandGrenade. * * @details * An even more detailed description of HolyHandGrenade. */ class HolyHandGrenade { private: int grenadeSize; ///< Specifies if you want a large or small grenade public: /** * @brief * Hurl thine Holy Hand Grenade towards thy foe. * * @details * Mercifully blows thine enemies to tiny bits. * * @param[in] count The number of the counting. */ void hurl(int count); ... };
Function and Method Comments
Every function should have a @brief section and, if appropriate, a @detail section that describes the function more in-depth.
Every parameter should be commented. Please try to use the direction attribute of the @param command ([in], [out], [in,out]).
If multiple return values are possible, it is preferable to use @retval to define each possible value that may be returned instead of @return. If there are many return values, or you just want to summarize what is returned, use @return to describe the return value.
Example:
#!highlight cpp /** * @brief * Return the sum of two positive integers. * * @details * Adds x and y and returns the result in z. * * @param[in] x First integer * @param[in] y Second integer * @param[out] z Holds the result of x+y * * @retval 0 success * @retval 1 failure, ints were not positive */ int sum(int x, int y, int *z) { if (x < 0 || y < 0) return 1; *z = x + y; return 0; }