본문 바로가기
개발

안전하고, 좋은 냄새가 나는 C++ 코드 만들기

by esstory 2007. 5. 30.

C++ 을 배운지 꽤 오래 되었지만, 아직도 코드 리뷰를 통해 다른 개발자들의 코드를 볼 때면 한숨이 나오는 경우가 많습니다.

이런 경우가 반복되다 보니, 예전에 몇 가지 코딩 규칙 비슷하게 만들어놓은 자료가 있어 포스팅해 봅니다.  자료가 만들다 말아 내용이 중구난방이네요..  앞으로도 계속 내용 보강해 나가겠습니다.

 

    포인트 핸들 및 윈도우 핸들 체크

-       함수로 전달된 포인터 인자나, new 로 생성한 포인터 등 모든 포인터는 사용하기 직전 포인터 검사를 수행

-       가급적 STL 컨테이너를 사용해서 아예 포인터를 사용하지 않는 것이 정신건강에 이롭다. (STL 자체적으로 메모리 생성 및 소멸)

-       메모리 LEAK 을 막기 위해 SMART POINT 와 같은 Wrapper 클래스를 만든다.

-       (윈도우 프로그램의 경우)윈도우 API 호출 직전 항상 윈도우 핸들이 정상인지 IsWindow 와 같은 함수로 검사한다.

 

    DRY(Don't Repeat Your Code)원칙

-       같은 코드를 여기 저기 중복해서 사용하지 말아야 한다. (☞ 실용주의 프로그래머 참고). 중복해서 사용할 경우 코드 량이 늘어날 뿐만 아니라 유지보수 cost 가 같이 늘어 나고, 추후 추가/개선/변경 등의 요구사항으로 인한 모듈 수정 시 여러 소스를 함께 수정해야 한다.

-       동일한 코드를 공용 루틴(함수)으로 개발 – 2~3줄 짜리 복잡한 if 문도 bool 를 리턴 하는 함수로 개발(Refactoring 참고)

 

    클래스간 종속성 최소화

-       대규모 프로젝트에서는 공통모듈이 변경되어도 이를 사용하는 모듈이 문제가 없도록 반드시 공통모듈은 인터페이스 기반(데이터가 없는, virtual 가상함수로만 구성된)으로 구현한다. (The C++ Programming Language 참고)

-       A 클래스 → B 클래스 → C 클래스를 사용할 경우 각 클래스는 자기가 직접 다루는 클래스(A B, B C) 만 알아야 한다. A 클래스는 C 클래스를 직/간접적으로 include 해서는 안되며 C 클래스의 변경으로 인해 A 클래스가 컴파일 되어서는 안 된다. A 클래스가 C 를 직접 접근할 경우가 있다면 B 클래스에 위임함수를 만들어 해결한다. (☞ 실용주의 프로그래머 참고)

-       B 클래스가 A 클래스로 어떤 데이터를 전달할 경우가 있다면(주로 이벤트 발생시 값을 전달하기 위해) A 클래스의 최소 인터페이스만을 B 클래스에 전달하여(COM 의 이벤트 소스 방식) 종속성을 최소화 한다. (Developer’s Workshop To COM and  ATL 3.0 참고)

 

    함수 인자 전달

-       함수의 인자는 최대 7개를 넘지 않아야 한다(Code Complete 2 참고)

-       클래스 인스턴스를 함수 인자로 넘겨서는 안 된다(특히 함수 인자로 CString 을 넘기는 경우가 많음. CString → const CString& CString*, const char* 등으로 수정한다. )

 

    오류조건을 먼저 검사하여 오류 체크로 인해 코드 가독성이 떨어지지 않도록 하자.

-       특정 오류조건이 발생하면 더 이상 함수 수행에 의미 없을 경우, 이러한 오류 조건들은 함수초입단계부터 먼저 확인해서 바로 리턴 한다

-       위와 같이 오류조건이 먼저 확인되면 프로그램 코드에서 if depth 가 줄어 들고 코드 읽기가 수월해 지는 장점이 있다.

Before

After

void CClass::OnTest()

{

 ...

 ...

 if (m_pWndMain)

 { 

  DoSomething1();

 }

 ...

 if (m_pWndMain)

 { 

  DoSomething2();

 }

 

}

void CClass::OnTest()

{

 if (m_pWndMain == NULL)

  return;

 ...

 ...

 DoSomething1();

 ...

 DoSomething2();

 

}

 

    긴 함수 쪼개기 (Refactoring 참고)

-       긴 함수는 작은 여러 개의 함수로 쪼갠다(Refactoring 책에 의하면 2-3줄 짜리 함수로까지 쪼개어서 코드 가독성을 높이도록 하고 있음)

-       작은 함수로 쪼개다 보면, 작은 함수를 재활용하게 될 수 있고

-       긴 함수보다 코드 읽기가 수월해 지며

-       결국 유지보수가 쉬워진다

 

    enum 값 선언 시 _START, _END 를 활용하자( CODE COMPLETE2 참고)

-       enum 으로 선언된 값들을 변수나 for loop 를 이용하여 반복 계산할 경우가 종종 있는데 이 경우 enum 시작과, 끝을 나타내는 값을 enum 선언에 포함하면 유용하게 사용할 수 있다.

-       추후 enum 에 값을 추가해야 할 경우 _END 값을 사용한 배열은 코드 변경없이 크기가 늘어남

-       For 루프 등에 _START, _END 을 사용할 수 있어 유지 보수에 유리

Before

After

enum WEEK_NAME

{

           SUNDAY                     = 0,

           MONDAY                    = 1,

           TUESDAY                    = 2,

           WEDNESDAY     = 3,

           THURSDAY       = 4,

           FRIDAY            = 5,

           SATERDAY        = 6,

};

 

int nWeeks[SATERDAY + 1];

}

enum WEEK_NAME

{

           WEEK_STAR       = 0,

           SUNDAY                     = 0,

           MONDAY                    = 1,

           TUESDAY                    = 2,

           WEDNESDAY     = 3,

           THURSDAY       = 4,

           FRIDAY            = 5,

           SATERDAY        = 6,

           WEEK_END        = 6,

};

 

int nWeeks[WEEK_END + 1];

 

 

    복잡한 제어문을 가진 루틴을 피하자  

-       If 문은 2 depth 이상 들어 갈 경우 refactoring 하라 (CODE COMPLETE2)

     대부분 코드를 제대로 이해하지 못해 복잡한 코드를 작성하고 있다.

     개발자 90% 2 depth 이상 들어가는 if 문장을 이해하지 못한다

-       IF~ELSE IF ~ELSE IF ~ …. ELSE 가 길게 이어질 경우 SWITCH 문으로 바꾼다

-       IF 문이 길게 늘어 질 경우 함수로 분리한다

-       C++ factory 개념으로 상속을 이용한 클래스를 만드는 방법도 활용


댓글