본문 바로가기
Programming/Effective C++ 3판

항목 2. #define을 쓰려거든 const, enum, inline을 떠올리자.

by deviAk 2008. 5. 29.
반응형
이유
1. 컴파일러는 선행 처리자를 밀어버리고 숫자 상수로 바꾸어 버리기 때문이다.

#define ASPECT_RATIO 1.653

위와 같이 코드를 썻다고 하면 ASPECT_RATIO 라는이름은 컴파일러가 쓰는 기호 테이블레 들어가지 않는다. 그래서 숫자 상수로 대체된 코드에서 컴파일 에러라도 발생하게 되면 골치가 아플 수 있다. 소스 코드엔 분명히 ASPECT_RATIO가 있었는데 에러 메시지엔 1.653이 있으니 말이다.

해결책

1. 매크로 대신 상수를 사용하자.

const double AspectRatio = 1.653;

AspectRatio는 언어 차원에서 지원하는 상수 타입의 데이터이기 때문에 당연히 컴파일러의 눈에도 보이며 기호 테이블에도 당연히 들어간다. 게다가 상수가 부동소수점 실수 타입일 경우에는 컴파일을 거친 최종 코드의 크기가 #define을 썼을 때보다 작게 나올 수 있다.

#define을 상수로 교체하려면 두 가지 경우만 특별히 조심하자.

1-1. 상수 포인터를 정의 하는 경우

- 상수 정의는 대게 해더 파일에 넣는 것이 상례이므로 포인터는 꼭 const로 선언해 주어야 하고, 이와 아울러 포인터가 가르키는 대상까지 const로 선언하는 것이 보통이다.

const char* const authorName = "Scott Meyers";

문자열 상수를 쓸 때 위와 같이 char* 기반의 문자열보다는 string 객체가 대체적으로 사용하기 괜찮다.

const std::string myName("Little");


1-2. 클래스 멤버로 상수를 정의하는 경우. (클래스 상수를 정의하는 경우)

어떤 상수의 유효범위를 클래스로 한정하고자 할 때는 그 상수를 멤버로 만들어야 하는데, 그 상수의 사본 개수가 한개를 넘지 못하게 하고 싶다면 정적(static) 멤버로 만들어야 한다.

class GamePlayer {
private:
 static const int NumTurns = 5;     // 상수 선언
 int scores[NumTurns];        // 상수를 사용하는 부분
 ...
}

NumTurns는 '선언(declaration)' 된 것이다. C++에서는 사용하고자 하는 것에 대해 '정의'가 마련되어 있어야 하는게 보통이지만, 정적 멤버로 만들어지는 정수류 타입의 클래스 내부 상수는 예외이다. 이들에 대해 주소를 취하지 않는 한, 정의 없이 선언만 해도 아무 문제가 없게 되어 있다.
단, 클래스 상수의 주소를 구한다든지, 주소를 구하지 않는데도 컴파일러가 정의를 달라고 떼쓰는 경우에는 별도의 정의를 제공해야 한다.

const int GamePlayer::NumTurns;     // NumTurns의 정의.

위의 상수의 정의는 구현 파일에 두어야 한다. 정의에는 상수의 초기값이 있으면 안되는데, 왜냐하면 클래스 상수의 초기값은 해당 상수가 선언된 시점에서 바로 주이지기 때문이다.



2. 클래스를 컴파일하는 도중에 클래스 상수의 값이 필요할 때는 '나열자 둔갑술'을 이용하자.

class GamePlayer {
private:
 enum { NumTurns = 5; };
 int scores[NumTurns];
}

나열자 둔갑술을 알아두면 좋은 이유는 다음과 같다.

2-1. 나열자 둔갑술은 동작 방식이 const보다는 #define에 가깝다. 주소를 얻는다든지 참조자를 쓴다든지 하는 것을 막을 수 있다. enum은 #define처럼 어떤 형태의 쓸데없는 메모리 할당도 절대 저지르지 않는다.


3. #define 을 사용한 매크로 약간의 버그가 있기 때문에 inline 함수에 대한 template을 사용하자.



이것만은 잊지 말자!
- 단순한 상수를 쓸 때는 #define보다 const 객체 혹은 enum을 우선 생각한다.
- 함수처럼 쓰이는 매크로를 만들려면 #define 매크로보다 인라인 함수를 우선 생각한다.


관련 링크
http://ikpil.tistory.com/401
http://ikpil.tistory.com/282
반응형