NALCG Coding Standards
- All code must be cross platform, ANSI C++. No dependencies on platform-specific headers and / or types are allowed (the only exception is when dealing with platform-specific features like windowing, which must be implemented for each platform separately).
- If you serialise / deserialise any data, subclass from Serializer and use its methods, it will insulate you from endianness issues. If you need to serialise any types it doesn't already handle, make sure you deal with endianness issues in the same way Serializer does (ie use native endianness by default but detect the inverse on reading and perform flipping if required).
C++ Standards compliance
- Always prefer the STL over custom containers / algorithms.
- Always prefer C++ techniques over C.
- Avoid C-strings (char* and functions like sprintf, strcpy, use std::string)
- Avoid old I/O routines (fopen et al, use <iostream>)
- Use abstract classes or templates not void*
- Use overloaded methods not varargs.
- Use the PImpl idiom to reduce dependencies between classes.
- Always use const-correctness. Methods taking non-primitive types as parameters should generally take them as const references, methods returning non-primitive types should generally return them as const references. Declare all methods that do not modify internal state 'const'. For lazy-update getter methods, declare the internal state which is lazy-updated 'mutable'.
- Prefer 'protected' over 'private' to encourage specialisation where appropriate
- Always declare destructors 'virtual' unless the class you are writing should not have any vtable (no other virtual methods).
- Avoid non-const by-ref parameters unless you have no other option. We prefer not to have in/our parameters since they are less intuitive.
Naming conventions & Documentation
- Classes, types and structures must be title case (MyNewClass).
- Methods and local variables must be camel case (myNewMethod).
- Member variables should be prefixed with 'm' (mInstanceVar), static member variables should be prefixed 'ms' (msStaticMemberVar). Do not use any other prefixing such as Hungarian notation.
- Enums should be named in title case, enum values should be all upper case
- Use verbose, descriptive names for classes, methods, variables - everything except trival counters. Code should be self-describing, don't be obtuse.
- Avoid using new/delete directly.
Use boost::shared_ptr instead
- Don't leak :(
- Indent with Spaces only, single indentation level is four (4) spaces. Tabs shall not be used anywhere else, but in the Makefile
- Insert a newline before an open brace (contentious I know!)
- Always insert spaces in between operators and operands (x + y, not x+y)
- Use parenthesis to make the operator precedence unambiguous, even when it is not required ((x * y) + 1, not x * y + 1)
- Fatal errors should always be dealt with though exception handling. No return-value error reporting.
- Whenever you make an assumption in your code, verify it with an assert().
- Use existing design patterns and identify them by their well known names. A good starting reference is the 'Gang of Four' book.
- Use strong encapsulation. Top-level interfaces should hide implementations and not require the user of the library to understand internals. Avoid public attributes except in structs.
- Don't use 'friend' if you can avoid it. Where classes need to collaborate on an internal implementation, prefix the methods they use to communicate with '_' (this is our demarcation for 'recommended for internal use only'). This can also be used to expose advanced functionality only intended for very skilled users.
If in doubt, do as the existing code does!