ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 안전하고, 좋은 냄새가 나는 C++ 코드 만들기
    개발 2007.05.30 19:15

    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 개념으로 상속을 이용한 클래스를 만드는 방법도 활용


    댓글 5

    • 프로필사진

      new가 상황에 따라서 null return이 아니라 메모리 익셉션을 던지기도 합니다. null 체크 했다고 모든 것이 끝난 것은 아니겠죠;;

      그리고 CString의 경우 const CString&이 빠졌네요. const reference만큼 좋은 것도 드뭅니다. const char * 는 약간 위험할 수 있습니다. CString이면 MFC쪽인것 같은데 내부 구현을 보면 LPCTSTR의 구현 특성상 사이드 이펙트가 가능합니다.

      2007.05.30 21:03 신고
      • 프로필사진

        답변감사합니다 ^^;
        모든 new 의 exception 을 각각 모듈에서 체크하지는 않고 보통은 글로벌 unhandled exception handler 에서 처리하고 있어 해당 내용은 굳이 언급하지 않았습니다. CString& 앞에 const 가 빠졌네요.^^; 본문수정할게요~

        2007.05.31 08:05 신고
    • 프로필사진

      너무 좋은 이야기 같아서 퍼갑니다 ㅡ.ㅜ 아직 초보라서 퍼가고 읽어보고 해보고 할께 많내요 ㅋ 좋은자료 감사합니다.~~~

      2008.04.14 19:46 신고
    • 프로필사진

      좋은정보 감사합니다.
      출처 남기고 퍼갈게요~ :)

      2011.01.13 19:29 신고
    • 프로필사진

      우와.... 감동 ㅠ
      출처남기고 퍼가겠습니다

      2015.03.15 02:04
Designed by black7375.