1. Readability first. (Your code should be your documentation most of the time.)
2. Crash/Assert early. Don't wait until the worst case happens to make the crash condition.
3. Follow IDE's auto formatted style unless you have really good reasons not to do so. (Ctrl + K + D in VC++)
4. Learn from existing code.
https://docs.google.com/document/d/1cT8EPgMXe0eopeHvwuFmbHG4TJr5kUmcovkr5irQZmo/mobilebasic?usp=gmail
class PlayerManager;
struct AnimationInfo;
void SomeMethod(const int someParameter)
{
int someNumber;
}
class SomeClass
{
public:
// a. Use pascal casing for public methods
void DoSomehting();
private:
// a. Use camel casing for other methods
void doSomething();
};
constexpr int SOME_CONSTANT = 1;
namespace abc
{
}
bool bFired; // for local and public member variable
bool mbFired; // for private class member variable
class ISomeInterface;
enum class eDirection
{
North,
South
};
class Employee
{
protected:
int mDepartmentID;
private:
int mAge;
};
uint32_t GetAge() const
{
return 0;
}
11. Use descriptive variable names e.g, index or employee instead of i or eunless it is a trivial index variable used for loops.
int OrderID;
int HttpCode;
// Use:
class Employee
{
public:
const string& GetName() const;
void SetName(const string& name);
private:
string mName;
};
// Instead of:
class Employee
{
public:
string Name;
};
14. Use only public member variables for a struct. No functions are allowed. Use pascal casing for the members of a struct.
struct MeshData
{
int32_t VertexCount;
};
16. Put external header files first, followed by in-house header files in alphabetic order if possible.
#include <undrdered_map>
#include <vector>
#include "AnimationInfo.h"
19. Use Visual Studio default for tabs. If you are not using Visual Studio, use real tabs that are equal to 4 spaces.
if (bSomething)
{
return;
}
23. Use precision specification for floating point values unless there is an explicit need for a double.
float f = 0.5f;
switch (number)
{
case 0:
break;
default:
break;
}
25. Always add predefined FALLTHROUGH for switch case fall through unless there is no code in the case statement. This will be replaced by [[fallthrough]] attribute coming in for C++17 after.
switch (number)
{
case 0:
DoSomething();
FALLTHROUGH
case 1:
DoFallthrough();
break;
case 2:
case 3:
DoNotFallthrough();
default:
break;
}
26. If default case must not happen in a switch case, always add Assert(false). In our assert implementation, this will add optimization hint for release build.
int GetAge() const;
void FibonacciRecursive();
a. list of friend classes
b. public methods
c. protected methods
d. private methods
e. protected variables
f. private variables
// Use:
const Anim* GetAnimByIndex(const int index) const;
const Anim* GetAnumByName(const char* name) const;
// Instead of:
const Anim* GetAnim(const int index) const;
const Anim* GetAnum(const char* name) const;
Anim* GetAnimByIndex(const int index);
const Anum* GetAnumByIndex(const int index);
34. Avoid use of const_cast. Instead create a function that clearly returns an editable version of the object.
35. Each class must be in a separate source file unless it makes sense to group several smaller classes.
class PlayerAnimation;
PlayerAnimation.cpp
PlayerAnimation.h
37. When a class spans across multiple files, these files have a name that starts with the name of the class, followed by an underscore and the subsection name.
class RenderWorld;
RenderWorld_demo.cpp
RenderWorld_load.cpp
RenderWorld_portals.cpp
class Renderer;
Renderer.h // all renderer interfaces called by games
Renderer.cpp // Renderer's Implementations which are to all platforms
Renderer_gl.h // RendererGL interfaces called by Renderer
Renderer_gl.cpp // RendererGL implementations
40. Use assert for any assertion you have. Assert is not recoverable. This can be replaced by compiler optimization hint keyword __assume for the release build.
42. Memory operations such as memset, memcpy and memmove also must be done through our own MemSet, MemCpy and MemMove.
void GetScreenDimension(uint32_t* const outWidth, uint32_t* const outHeight)
{
Assert(outWidth);
Assert(outHeight);
}
void AddMesh(Mesh* const mesh)
{
mMeshCollection.push_back(mesh);
}
void Update(void* const something)
{
}
enum class eVisibilityFlags
{
};
49. Do not add size specifier for enum unless you need that specific size (e.g, for serialization for data members)
enum class eDirection : uint8_t
{
North,
South
};
51. When default parameters are used, restrict them to natural immutable constants such as nullptr, false or 0.
#define NUM_CLASSES (1)
int& number;
int* number;
class SomeClass
{
public:
int32_t Count;
public:
void Func(const int32_t Count)
{
for (int32_t count = 0; count != 10; ++count)
{
// Use Count
}
}
}
// BAD:
int counter, index;
// GOOD:
int counter;
int index;
61. Do not use const member variables in a struct or class simply to prevent modification after initialization. Same rule is applied to reference(&) member variables.
62. Take advantage of NRVO, when you are returning a local object. This means you need to have only one return statement inside your function. This applies only when you return an object by value.
enum class eDirection
{
North,
South
};
5. Use unique_ptr when a object lifetime is solely handled inside a class. (i.e. new in constructor delete in destructor)
7. Do not use auto unless it is for a iterator or new keyword is on the same line, showing which object is created clearly.
8. Do not manually perform return value optimization using std::move. It breaks automatic NRVO optimization.
// Use:
constexpr int DEFAULT_BUFFER_SIZE = 65536;
// Instead of:
const int DEFAULT_BUFFER_SIZE = 65536;