2009년 5월 18일 월요일

05장. 구현

항목 26. 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자.

  • 루프 안에서의 변수 정의
    • 대입이 생성자-소멸자 쌍보다 비용이 덜 들고, 전체 코드에서 수행 성능에 민감한 부분을 건드리는 중이 아니라면 루프안에서 변수를 정의 하고 쓰자.
  • 변수 정의는 늦출 수 있을 때까지 늦춥시다. 프로그램이 더 깔끔해지며 효율도 좋아집니다.

 

항목 27. 캐스팅은 절약, 또 절약! 잊지 말자.

  • "어떤 일이 있어도 타입 에러가 생기지 않도록 보장한다." C++ 동작 규칙.
  • 구형 스타일 캐스트
    • (T)표현식
    • T(표현식)
  • C++ 스타일 캐스트
    • const_cast
    • dynamic_cast
    • reinterpret_cast
    • static_cast
  • 신형 스타일 캐스트가 좋은 이유
    • 알아보기 쉽다.
    • 캐스트 사용 목적이 좁혀져서, 사용 에러 진단에 용이하다.
  • 객체 하나가 가질수 있는 주소가 오직 한 개가 아니라 그 이상이 될 수 있음.
  • 가상 함수에서 베이스 클래스 함수를 호출할 경우 캐스팅 하지 말고 base::function() 을 호출하도록 하자.
  • dynamic_cast 은 정말 느리다.. -_-; (일부 컴파일러는  strcmp 사용해서 vtable 검사)
  • 폭포식 dynamic_cast ;;; 과연 쓰는 사람이 있을까? -_-;; (절대 쓰지 말자.)
  • 다른 방법이 가능하다면 캐스팅은 피하십시오. 특히 수행 성능에 민감한 코드에서 dynamic_cast는 몇번이고 다시 생각하십시오. 설계 중에 캐스팅이 필요해졌다면, 캐스팅을 쓰지 않는 다른 방법을 시도해 보십시오.
  • 캐스팅이 어쩔 수 없이 필요하다면, 함수 안에 숨길 수 있도록 해 보십시오. 이렇게 하면 최소한 사용자는 자신의 코드에 캐스팅을 넣지 않고 이 함수를 호출할 수 있게 됩니다.
  • 구형 스타일의 캐스트를 쓰려거든 C++ 스타일의 캐스트를 선호하십시오. 발견하기도 쉽고, 설계자가 어떤 역활을 의도했는지가 더 자세히 들러납니다.

 

 

항목 28. 내부에서 사용하는 객체에 대한 '핸들'을 반환하는 코드는 되도록 피하자.

  • 클래스 데이터 멤버는 아무리 숨겨봤자 그 멤버의 참조자를 반환하는 함수들의 최대 접근도에 따라 캡슐화 정도가 정해진다.
  • 무효참조 핸들이 가장 큰 문제이다. ( 핸들을 따라 갔는데 실제 객체의 데이터가 없는 경우 )
  • 어떤 객체의 내부요소에 대한 핸들(참조자, 포인터, 반복자)을 반환하는 것은 되도록 피하세요. 캡슐화 정도를 높이고, 상수 멤버 함수가 객체의 상수성을 유지한 채로 동작할 수 있도록 하며, 무효참조 핸들이 생기는 경우를 최소화할 수 있습니다.

 

항목 29. 예외 안전성이 확보되는 그날 위해 싸우고 또 싸우자!

  • 예외 안전성을 확보하려면 두 가지의 요구사항을 맞추어야 한다.
    • 자원이 새도록 만들지 않는다.
      • 자원 관리 전담 객체를 만들어 해결하자.
    • 자료구조가 더렵혀지는 것을 허용하지 않는다.
      • 예외 안전성 세 가지 보장중에 하나를 제공하자.
  • 기본적인 보장(basic guarantee)
    • 함수 동작중 예외가 발생하면, 실행중인 모든 것들을 유효한 상태로 유지하겠다는 보장.
    • 자료구조를 더럽히지 않으며, 모든 객체의 상태는 내부적으로 일관성을 유지한다.
    • 하지만 프로그램 상태가 정확히 어떠한지 예측이 안 될 수도 있다. 함수를 만든 사람만이 알수있다.
  • 강력한 보장(strong guarantee)
    • 함수 동작중 예외가 발생하면, 프로그램 상태를 절대로 변경하지 않겠다는 보장.
    • 원자적인 동작을 수행한다.
    • 함수가 성공적으로 실행을 마친 후의 상태, 함수가 호출 되기전의 상태 두 가지만 존재.
  • 예외불가 보장(nothrow guarantee)
    • 예외를 절대로 던지지 않겠다는 보장.
    • 기본 제공 타입의 모든 연산은 예외불가 보장.
    • 예외 지정
      • void something() throw(int)   -   int 예외 발생
      • void something() throw()   -   예외를 발생하지 않음.
      • void something()   -   임의의 예외를 발생
    • uncaught excetion, unexpected exception 발생 가능.
    • set_terminate, set_unexpected 함수로 handler를 등록 가능. (vc9.0 미구현, gcc 3.4.5 구현)
  • 함수 부수 효과(side effect) 때문에 강력한 보장을 하기 힘들다.
  • 효율 문제도 있기때문에 실용성이 확보되는 경우에만 강력한 보장을 제공하는데 힘쓰자.
  • 예외 안전성이 없는 함수를 한개라도 쓰면 그 시스템은 전부 예외에 안전하지 않은 시스템이 된다.
  • 예외 안전성을 갖춘 함수는 실행 중 예외가 발생되더라도 자원을 누출시키지 않으며 자료구조를 더럽힌 채로 내버려 두지 않습니다. 이런 함수들이 제공할 수 있는 예외 안전성 보장은 기본적인 보장, 강력한 보장, 예외 금지 보장이 있습니다.
  • 강력한 예외 안전성 보장은 '복사-후-맞바꾸기' 방법을 써서 구현할 수 있지만, 모든 함수에 대해 강력한 보장이 실용적인 것은 아닙니다.
  • 어떤 함수가 제공하는 예외 안전성 보장의 강도는, 그 함수가 내부적으로 호출하는 함수들이 제공하는 가장 약한 보장을 넘지 않습니다.

 

항목 30. 인라인 함수는 미주알고주알 따져서 이해해 두자.

  • 함수의 길이가 길면 페이징 횟수가 늘어나고, 명령어 캐시 적중률이 떨어질 가능성이 높다. 코드 비대화.
  • 반대로 굉장히 짧으면 함수 본문이 함수 호출문보다 작아질 수도 있다. 명령어 캐시 적중률도 높아진다.
  • 암시적 인라인 요청(정의 부분에 본문 추가), 명시적 인라인 요청(inline 키워드 사용)
  • 보통 함수에 루프문, 재귀 호출, virtual 함수가 있으면 인라인 시키지 않는다.
  • 함수 포인터를 이용하면 인라인 시키기 않는다.
  • 라이브러리 설계할때는 바이너리 업그레이드를 제공할 수 없다.
  • 함수 인라인은 작고, 자주 호출되는 함수에 대해서만 하는 것으로 묶어둡시다. 이렇게 하면 디버깅 및 라이브러리의 바이너리 업그레이드가 용이해지고, 자칫 생길 수 있는 코드 부풀림 현상이 최소화되며, 프로그램의 속력이 더 빨라질 수 있는 여지가 최고로 많아집니다.
  • 함수 템플릿이 대개 헤더 파일에 들어간다는 일반적인 부분만 생각해서 이들을 inline으로 선언하면 안 됩니다.

 

항목 31. 파일 사이의 컴파일 의존성을 최대로 줄이자.

  • 표준 라이브러리 구성요소는 전방 선언을 하면 안된다.
  • 정의부에 대한 의존성(dependencies on definitions)을 선언부에 대한 의존성(dependencies on declarations)으로 바꾸는게 컴파일 의존성을 최소화 하는 핵심이다.
    • 객체 참조자 및 포인터로 충분한 경우에는 객체를 직접 쓰지 않습니다.
    • 할 수 있으면 클래스 정의 대신 클래스 선언에 최대한 의존하도록 만듭니다.
    • 선언부와 정의부에 대해 별도의 헤더 파일을 제공합니다.
  • pimpl 관용구("pointer to implementation") 사용. (핸들 클래스 - 구현 클래스)
  • 인터페이스 클래스 사용. 객체 생성 수단이 있어야 한다.( 보통 팩토리 함수 사용(가상 생성자) )
  • 인라인 함수를 쓰지 못한다.
  • 구현부가 바뀌었을때 사용자에게 미칠 파급 효과를 최소로 만들수 있다.
  • 컴파일 의존성을 최소화하는 작업의 배경이 되는 가장 기본적인 아이디어는 '정의' 대신에 '선언'에 의존하게 만들자는 것입니다. 이 아이디어에 기반한 두 가지 접근 방법은 핸들 클래스와 인터페이스 클래스입니다.
  • 라이브러리 헤더는 그 자체로 모든 것을 갖추어야 하며 선언부만 갖고 있는 형태여야 합니다. 이 규칙은 템플릿이 쓰이거나 쓰이지 않거나 동일하게 적용합니다.

 

 

이 글은 스프링노트에서 작성되었습니다.

댓글 없음:

댓글 쓰기