Personal C++ Style Guide
I’ve been thinking recently that I should write a style guide for personal C++ code. I’ve found the need to do this as I’ve found myself doing different things at different times and contradicting myself in several places. Also the lack of a clearly defined style guide at companies I think has harmed the code style in general. Note however that if I am working in existing source there is no choice but to assume the same style as the existing code. Imposing a new style of code in existing code makes the code unreadable and is bad practice.
I’ve read a lot of these at other locations and taken the ones I agree with. Please note that this is an evolving document that will be added to as I find more cases that I feel need style definitions.
Defines
- The #define pre-processor directive shall not be used to define constant values. Instead, the
const qualifier shall be applied to variable declarations to specify constant values. - When using #include, use
for platform or other project includes and “header.h” for same project includes
Includes
- When using #include, use
for platform or other project includes and “header.h” for same project includes - Declarations of classes that are only accessed via pointers (*) or references (&) should be
supplied by forward headers that contain only forward declarations.
General Code Rules
- Source lines will be kept to a length of 120 characters or less.
- Each expression-statement will be on a separate line. The following is not allowed:
if(var == a) val = 0;
- Braces (“{}”) which enclose a block will have nothing else on the line except comments (if
necessary). - Braces (“{}”) which enclose a block will be placed in the same column, on separate lines
directly before and after the block. - C++ style casts (const_cast, reinterpret_cast, and static_cast) shall be used instead of the
traditional C-style casts. - All switch statements that do not intend to test for every enumeration value shall contain a
final default clause. - The increment expression in a for loop will perform no action other than to change a single
loop parameter to the next value for the loop. - Floating point variables shall not be tested for exact equality or inequality. We should use epsilon and use subtraction for tests on comparison to equality
- C++ exceptions shall not be used (i.e. throw, catch and try shall not be used.)
- Operators should have a space at either side of them e.g.
// wrong if(x
Filename Naming Conventions
- All filenames will start with an uppercase letter and each consequent word have an uppercase letter e.g. PackageManager.h
- Prefixes should not be used, they cause the reuse of a class difficult at a later point e.g. MTPackageManager.
Class Naming Conventions
- All classes will start with an uppercase letter and each consequent word have an uppercase letter e.g. SteamCommunicator
Variable Naming Conventions
- Local variables should always start with a lowercase letter
- Always attempt to use the smallest datatype possible, i.e use a short instead of an integer where possible.
- Member variables should have a 'm' prefix, e.g. m_count
- Const members (or anonymous members) should have a 'k' prefix
- Static variables should have a 's' prefix. Static members should have a 'm' prefix.
- Global variables should have a 'g' prefix.
- All variables should be initialised if possible in the constructor
- Only 1 variable should be defined per line e.g
// incorrect int32 first button_on_top_of_the_left_box, i;
Pointers
- Pointers should have the 'p' prefix.
- The dereference operator ‘*’ and the address-of operator ‘&’ will be directly connected with the type-specifier.
// incorrect int *pInt; // Correct int* pInt; // incorrect int &rInt; // correct int& rInt;
Function Naming Conventions
- Functions should start with a lowercase letter and each consequent word have an uppercase letter e.g. listProducts
- Underscores shall NOT be used
- Any immutable/read-only parameters shall use a const reference. The exception to this rule is PODs which can be const but need not be a reference.
- Any reference non-const parameters shall use the 'r' prefix. This is to indicate to the method's code that the parameter is effectively an 'out' or return value
- Any parameter that is a pointer or smart point should use the 'p' prefix.
- A member function that does not affect the state of an object (its instance variables) will be declared const.
- A class will have friends only when a function or object requires access to the private elements of the class, but is unable to be a member of the class for logical or efficiency reasons.
- Functions shall always be declared at file scope or in anonymous namespaces.
- Functions with more than 7 arguments will not be used.
- Functions will have a single exit point, functions should not return early or have multiple exit points. This can be confusing when debugging and difficult to understand
- If a function returns a status code or boolean, this status or boolean MUST be tested and at least logged if something unexpected happens
- Only functions with 1 or 2 statements should be considered candidates for inline functions.
- Trivial accessor and mutator functions should be inlined and the number of accessor and mutator functions should be minimized.
Constructors & Destructor
- Unnecessary default constructors shall not be defined.
- Initialization of nonstatic class members will be performed through the member initialization
list rather than through assignment in the body of a constructor. - Members of the initialization list shall be listed in the order in which they are declared in the
class. If possible the compiler will issue warnings for variables that are defined out of order. - A copy constructor and an assignment operator shall be declared for classes that contain
pointers to data items or nontrivial destructors. - A copy constructor shall copy all data members and bases that affect the class invariant (a
data element representing a cache, for example, would not need to be copied). - All base classes with a virtual function shall define a virtual destructor.
- Avoid doing complex initialization in constructors (in particular, initialization that can fail or that requires virtual method calls).
- Use the C++ keyword explicit for constructors with one argument.
- ou must define a default constructor if your class defines member variables and has no other constructors. Otherwise the compiler will do it for you, badly.
Operators & Overloads
- The default copy and assignment operators will be used for classes when those operators
offer reasonable semantics. - An assignment operator shall return a reference to *this.
- An assignment operator shall assign all data members and bases that affect the class invariant
(a data element representing a cache, for example, would not need to be copied). - When two operators are opposites (such as == and !=), both will be defined and one will be
defined in terms of the other.
Typedefs
- Typedefs should start with an uppercase letter and each consequent word should have an uppercase letter. The name of the type should indicate the type of the object eg. ProductMap.
- Container typedefs should always have an interator and const iterators defined:
typedef ProductMap::iterator ProductMapIter typedef ProductMap::const_iterator ProductMapConstIter
Enumerations
- Enums should always start with an uppercase and each subsequent word start with an uppercase letter e.g. DisplayTypes
- Enum types should have an 'e' prefix and use the definition name at the start of the name e.g.
enum DisplayType { eDisplayTypeBlock, eDisplayTypeInline, eDisplayTypeMax }; - The enum should always contain a 'max' enum type, this is to facilitate iterating through the enums.
If statements
- When mutable variables are compared with a constant (or NULL) the style should always be as follows:
if(12 == x) { } - If statements should always have curly brackets and should start on the line after the if statement.
For statements
- For statements should always have curly brackets and they should start on the line after the for statement
Comments
- Standard ('//') comments and comment blocks ('/** ... **/') are the only comments allowed
- Code commented should should be deleted, this is the whole point of source control.
- PRE and POST conditions of functions should be commented in the header for a class
// PRE(pPointer) // POST(pPointer) void doSomething(pPointer);
I've attached my personal C++ and Objective C template classes which are effectively skeletons and to be used as a starting point for new classes.
CPPTemplate.h
CPPTemplate.cpp
ObjectiveCTemplate.h
ObjectiveCTemplate.m