Rule of Thumb

가독성 우선(항상 코드가 문서여야 함)
크래쉬/조기경사례 최악의 상황이 닥칠 때까지 기다리지 마라.
그렇게 하지 않을 이유가 없다면 IDE의 자동 포맷된 스타일을 따르십시오(VC++의 Ctrl + K + D)
기존 코드에서 학습

 

References

Unreal engine 4 coding standard

Doom 3 Code Style Conventions

IDesign C# Coding Standard

 

1. 네이밍 규칙 및 스타일

 

클래스 및 구조체 : 파스칼(Pascal)
class PlayerManager;
struct AnimationInfo;

 

지역 변수 및 지역 함수 파라미터 : 카멜(camel)
void SomeMethod(const int someParameter);
{
  int someNumber;
}

 

퍼블릭 함수엔 파스칼
public:
  void DoSomething();

프라이빗 함수엔 카멜
private:
  void doSomething();


상수는 _와 대문자
constexpr int SOME_CONSTANT = 1;


네임 스페이스는 전부 소문자
namespace abc{};


부울 변수에 대해서는 퍼블릭, 프라이빗 구분
bool bFired; // for local and public member variable
bool mbFired; // for private class member variable


인터페이스는 접미사 I로 시작
class ISomeInterface;


이넘은 e로 시작
enum class eDirection
{
  North,
  South
}


멤버 변수(프로텍티드, 프라이빗)는 m으로 시작
class Employee
{
protected:
  int mDepartmentID;
private:
  int mAge;
}

 

리턴 값이 있는 함수는 함수명 안에 리턴 내용을 명시
uint32_t GetAge() const;


단순 루프에 쓰는 문자가 아닌 이상, 용도를 지칭하는 변수를 사용

index or employee instead of i or e unless it is a trivial index variable used for loops.

 

뒤에 추가 단어가 없는 경우에는 약자로 된 모든 문자를 대문자로 사용
int OrderID;
int HttpCode;


클래스 멤버 변수에 항상 setter 및 getter 사용
Use:
class Employee
{
  public:
    const string& GetName() const;
    void SetName(const string& name);
  private:
    string mName;
}
Instead of:
class Employee
{
  public:
    string Name;
}


구조체는 반드시 퍼블릭 멤버 변수를 가지도록 하며, 함수를 가지지 않도록 하고

멤버변수 네이밍에 대해서는 파스칼을 사용
struct MeshData
{
  int32_t VertexCount;
}


외부 헤더 파일에는 #include<> 를 사용

내부 헤더 파일에는 #include ""  를 사용


외부 헤더 파일을 먼저 입력한 다음 가능하면 내부 헤더 파일을 알파벳 순서로 넣기
#include <vector>
#include <unordered_map>
#include "AnimationInfo.h"


There must be a blank line between includes and body.


#pragma once를 모든 헤더파일 첫 부분에 사용. 중복 인클루드를 막음


탭은 기본적으로 4칸 띄어쓰기로


로컬 변수를 선언하고 쓸때는 쓰이는 가장 가까운 곳에 쓰기. 선언을 최대한 미루기.


brace ({) 개행해서 쓰기.

if

{

}

 

한줄의 내용이라도 개행해서 쓰기.
if (bSomething)
{
  return;
}

 

더블을 사용하지 않는 한 f를 붙여서 플롯값에 대해 명시하기.
float f = 0.5f;


스위치 문은 디폴트 케이스를 항상 만들기.
switch (number)
{
  case n:
    ...
    break;
  default:
    break;


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 later
switch (number)
{
case 0:
  DoSomething();
  FALLTHROUGH
case 1:
  DoFallthrough();
  break;
case 2:
case 3:
  DoNotFallthrough();
default:
  break;
}


스위치 문에서 default 가 발생하지 않아야 하는 경우 항상 Assert(false)를 추가. 릴리즈 구축시 최적화에 도움됨.
switch (type)
{
  case 1:
    ...
    break;
  Default:
    Assert(false, "unknown type");
    break;
}


함수 인자값과 로컬 변수에 대해 최대한 const를 사용.


멤버 함수내 값이 변경될일 없다면 반드시 const를 사용.
int GetAge() const;


const 값을 리턴하지 말 것. 참조와 포인터에만 사용할 것.


재귀함수는 함수 네이밍안에 재귀함수라는 내용이 들어있도록 할 것.
void FibonacciRecursive();


클래스의 구성은 아래와 같은 순서를 따르자.

-list of friend classes

-public methods

-protected methods

-private methods

-protected variables

-private variables

 

함수의 오버로딩은 최대한 피하기.
Use:
const Anim* GetAnimByIndex(const int index) const;
const Anim* GetAnimByName(const char* name) const;

Instead of:
const Anim* GetAnim(const int index) const;
const Anim* GetAnim(const char* name) const;


const를 사용하기 위한 오버로딩은 예외로 허락
Anim* GetAnimByIndex(const int index);
const Anim* GetAnimByIndex(const int index) const;


const_cast는 사용하지 말 것.


여러 개의 작은 클래스를 그룹화하는 것이 타당하지 않다면 각 클래스는 별도의 소스 파일을 만들것. 


파일 이름은 최상위 클래스 이름과 동일해야 한다.
class PlayerAnimation;

PlayerAnimation.cpp
PlayerAnimation.h


클래스가 여러 파일에 걸쳐 있을 때, 파일은 클래스 이름 + 밑줄 및 하위 섹션 이름 순으로 시작하는 이름으로.
class RenderWorld;
RenderWorld_load.cpp
RenderWorld_demo.cpp
RenderWorld_portals.cpp


Platform specific class for "reverse OOP" pattern uses similar naming convention
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


C표준 대신 자체 버젼의 Assert를 사용.


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.

모든 메모리 할당은 New 와 Delete 로만 이루어질것.


Memory operations such as memset, memcpy and memmove also must be done through our own MemSet, MemCpy and MemMove.


어떤 이유로든 nullptr이 필요하지 않다면 일반적으로 참조(&)를 포인터보다 선호.

 

매개 변수에 포인터를 사용. 또한 기능 매개변수를 out을 접두사로 사용.
function:
void GetScreenDimension(uint32_t* const outWidth, uint32_t* const  outHeight)
{
}

caller:
uint32_t width;
uint32_t height;
GetScreenDimension(&width, &height);


위의 출력 변수는 null이어서는 안된다. Assert를 사용해라.
void GetScreenDimension(uint32_t* const outWidth, uint32_t* const  outHeight)
{
  Assert(outWidth);
  Assert(outHeight);
}

 

파라미터를 내부적으로 저장하려면 포인터를 사용해라.
void AddMesh(Mesh* const mesh)
{
  mMeshCollection.push_back(mesh);
}


매개 변수가 generic void* 매개 변수여야 하는 경우 포인터 사용
void Update(void* const something)
{
}


비트 플래그 이넘의 이름은 반드시 Flags를 붙임.
enum class eVisibilityFlags
{
}


특정 크기(예: 데이터 멤버의 직렬화)가 필요한 경우가 아니면 Enum에 대한 크기 지정자를 추가하지 마라.
enum class eDirection : uint8_t
{
  North,
  South
}


Prefer overloading over default parameters


When default parameters are used, restrict them to natural immutable constants such as nullptr, false or 0.


Prefer fixed-size containers whenever possible.


reserve() dynamic containers whenever possible.


Always put parentheses for defined numbers
#define NUM_CLASSES (1)


Prefer constants over defines


Always use forward declaration if possible instead of using includes


All compiler warnings must be addressed.


Put pointer or reference sign right next to the type
int& number;
int* number;


Shadowed variables are not allowed.
class SomeClass
{
public:
    int32_t Count;
public:
    void Func(const int32_t Count)
    {
        for (int32_t count = 0; count != 10; ++count)
        {
            // Use Count
        }
    }
}


Declare only one variable per line

BAD:

int counter, index;

 

GOOD: 

int counter;

int index;


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.


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.

<<<__restrict keyword

 

2. Modern Language Features

 

override and final keywords are mandatory


Use enum class always
enum class eDirection
{
  North,
  South
}


Use static_assert over Assert, if possible.


Use nullptr over NULL


Use unique_ptr when a object lifetime is solely handled inside a class. (i.e. new in constructor delete in destructor)


Range-based for are recommended where applicable


Do not use auto unless it is for a iterator or new keyword is on the same line, showing which object is created clearly


Do not manually perform return value optimization using std::move. It breaks automatic NRVO optimization.

Move constructor and move assignment operator are allowed.


Use constexpr instead of const for simple constant variables
constexpr int DEFAULT_BUFER_SIZE = 65536

Instead of
const int DEFAULT_BUFER_SIZE = 65536
.

  1. <<<TBD: constexpr

  2. <<<TBD: Lambda

  3. <<<TBD: do not use shared_ptr

3. Project Settings and Project Structure

 

Visual C++: Always use property sheets to change project settings

프로젝트 설정에서 컴파일 경고를 비활성화하지 마라. #pragma를 사용하라.




+ Recent posts