2013년 4월 17일 수요일

[Effective C++]항목2 #define을 쓰려거든 const, enum, inline을 떠올리자

#define ASPECT_RATIO 1.653

우리에겐 이미 ASPECT_RATIO가  기호식 이름(symbolic name)으로 보이지만 컴파일러에겐 전혀보이지 않습니다. 소스 코드가 어떻게든 컴파일러에게 넘어가기 전에 선행 처리자가 밀어버리고 숫자 상수로 바꾸어 버리기 때문입니다. 그 결과로, ASPECT_RATIO라는 이름은 컴파일러가 쓰는 기호 테이블에 들어가지 않지요. 그래서 숫자 상수로 대체된 코드에서 컴파일 에러라도 발생하게 되면 꽤나 헷갈릴 수 있습니다.

이 문제의 해결법은 메크로 대신 상수를 쓰는 것입니다.
const double AspectRatio = 1.653;

AspectRatio는 언어 차원에서 지원하는 상수 타입의 데이터이기 때문에 당연히 컴파일러의
눈에도 보이며 기호 테이블에도 당연히 들어갑니다. 게다가 (위의 예처럼) 상수가 부동소수점 실수 타입일 경우에는 컴파일을 거친 최종 코드의 크기가 #define 을 썻을 때보다 작게 나올수 있습니다. 매크로를 쓰면 코드에 ASPECT_RATIO가 등장하기만 하면 선행 처리자에 의해 1.653으로 모두 바뀌면서 결국 목적 코드 안에 1.653의 사본이 등장 횟수만큼 들어가게 되지만, 상수 타입의 AspectRatio는 아무리 여러번 쓰이더라도 사본은 딱 한개만 생기기 때문입니다.

#define 을 상수로 교체하려는 분께는 딱 두 가지 경우만 특별히 조심하라고 말씀드리겠습니다.
첫째 상수 포인터(constant pointer)를 정의 할경우 꼭 포인터와 포인터가 가리키는 대상 까지 모두 const로 선언하는 것이 보통입니다.
ex) const char* const authorName = "Scott Meyers";
두 번째 클래스 멤버로 상수를 정의하는 경우, 즉 클래스 상수를 정의하는 경우입니다.
상수의 사본 개수가 한 개를 넘지 못하게 하고 싶다면 정적(static) 멤버로 만들어야 합니다.
다음을 보시죠
class GamePlayer{
 private:
static const int NumTurns = 5;//상수 선언, 정의가 아니니 주의하세요.
int scores[NumTurns];//상수를 사용하는 부분
}
C++에서는 여러분이 사용하고자 하는 것에 대해 '정의'가 마련되어 있어야 하는게 보통이지만, 정적 멤버로 만들어지는 정수류(각종 정수 타입, char, bool 등) 타입의 클래스 내부 상수는 예외입니다.

const static으로 선언되는 멤버변수는 NumTurns 같이 선언과 동시에 초기화가 가능하다.
클래스 내에 선언된 const 멤버변수(상수)의 초기화는 이니셜라이져를 통해야만한다.
클래스 내에 선언된 static 멤버변수는 클래스 외부에서 초기하 해야 한다.

정리중....

댓글 없음:

댓글 쓰기