C++ Coding Style
I often find that partway through a project I get the urge to rethink certain aspects of the style I'm using. I think that's partly because I've never really sat down and decided on a style; usually I just get started with whatever style I most recently matched at work. My intention here is to have a solid coding style doc to reference for any personal projects. It may be a living document that changes as I encounter new arguments for and against different styles but it should always reflect my current stance.
Rules
General rules
- All lines should be less than 120 characters long.
- No function should be greater than 100 lines.
- Prefer descriptive variable names over single character ones. Abbreviations are acceptable.
- Avoid nesting more than 3 levels deep of loops or
if
s - Use tabs for indentation to block level and spaces for alignment.
Avoid Raw Loops
This rule was taken from: https://channel9.msdn.com/Events/GoingNative/2013/Cpp-Seasoning
Raw loops reduce readability of code and should be pulled out of larger functions.
The code:
// Do stuff above
u32 max = 0;
for ( int idx = 0; idx < collectionSize; ++idx )
{
if ( collection[idx] > max )
max = collection[idx];
}
// Do more stuff below
Should instead be written as
// Do stuff above
u32 max = MaxOf ( collection, collectionSize );
// Do more stuff below
This is a contrived example and also illustrates a case where using standard algorithms would be a better choice.
Naming Convention
Classes will begin with a capital letter and every new work will have it's first letter capitalized
class CamelCase;
Functions will follow the same naming convention of classes.
Plain Old Data (POD) types will be marked as structs and will be lower case with words separated by underscores
struct plain_old_data;
Variables will follow the naming convention of s_dName
where s
is the scope and d
is the data type which will only be present in the case of primitive types: n
for signed integer
, u
for unsigned integer
, f
for float
, p
for pointer, s
for string
(std or c-style) and b
for bool
. Scope may be omitted for local variables ( in which case the underscore is also omitted ); in other cases it will be m
for member and g
for global or static at the class level.
Const
The first const
may go before or after the type. While before is considered more conventional, having the const after the type makes it more consistent with the other instances of const ( which also affect the previous declaration ).
Const functions should be preferred to non const functions. Pure functions should, in particular, be preferred as it increases code readability and reduces likelihood of unwanted state mutation.
If a reference is passed into a function it must be const. If a function is meant to mutate the state of a passed in variable that variable must be passed in as a pointer. This is to ensure all state mutation is explicit on the side of the function caller.
Whitespace
Parenthesis spacing
There should be whitespace after every opening parenthesis and before every closing parenthesis. Assignment and math operators should be surrounded by whitespace. Commas should have whitespace after them.
T variable = Function( arg0, arg1 );
T variable2 = variable + variable;
There should also be a whitespace after an if
and before the parenthesis. There can optionally be one after a functions name and before the parenthesis.
if ( condition )
T0 Function ( T1 arg )
Logical spacing
Whitespace can be used to break up long functions into logical pieces. The better solution in many cases where this applies is to pull the functionality into it's own function. In the cases where doing so is not better, be sure to add a comment before the block describing the functionality.
There should also be spacing before after every Access Modifier in a class definition. The only exception to this is if a class definition starts with an access Modifier in which case it doesn't need the space before. This also applies to struct definitions.
class Class
{
public:
T0 Function ();
private:
u32 m_uVar;
}
Nested block spacing
There will be a linebreak before and after every opening brace and closing one. The only exception to this is when both opening and closing brace can fit on the same line. This exception does not apply if there are multiple related blocks ( such as an if
followed by one or more else if
s and/or an else
.
// Acceptable
T0 Function( T1 arg )
{
// code
}
// Unacceptable
T0 Function( T1 arg ) {
// code
}
// Also acceptable
if ( condition ) { /* code */ }
// Unacceptable
if ( condition ) { /* code */ }
else { /* code */ }
// Acceptable
if ( condition )
{
// code
}
else
{
// code
}
This applies also to else
and else if
meaning they must both be on their own line.