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

Jangmanbo·2023년 2월 2일
0

Effective C++

목록 보기
2/33

가급적 선행 처리자보다 컴파일러를 더 가까이 하자!


사례1: 매크로 상수

#define ASPECT_RATIO 1.653

소스코드가 컴파일러에게 넘어가기 전에 선행 처리자가 ASPECT_RATIO를 숫자 상수로 바꿨기 때문에, 컴파일러에겐 ASPECT_RATIO가 전혀 보이지 않는다. (->컴파일러가 쓰는 기호 테이블에도 없다.)

때문에 파일 에러라도 발생한다면 소스 코드에서는 ASPECT_RATIO이지만, 에러 메시지엔 1.653만 보이게 된다.
또한 코드에 존재하는 모든 ASPECT_RATIO를 1.653으로 바꾸기 떄문에 1.653의 사본이 등장 횟수만큼 들어간다.

해결법

const double AspectRatio=1.653;

이렇게 매크로 대신 상수를 쓰면 AspectRatio는 컴파일러에도, 기호 테이블에서도 보이게 된다.
또한 사본이 딱 한 개만 생기게 된다.

주의할 점

  1. 상수 포인터를 정의하는 경우
    상수 포인터 : 주소값을 바꿀 수 없음. (가리키는 대상의 값은 변경 가능)
    이때 포인터가 가리키는 대상까지 const로 선언하자!
	const char * const authorName="Scott Meyers";	// C 스타일 상수 포인터
	const std::string authorName("Scott Meyers");	// C++ 스타일, char*보다 추천
  1. 클래스 상수를 정의하는 경우
    클래스 상수 : 상수인 클래스 멤버
    상수의 사본 개수가 한 개를 넘지 못하게 하고 싶다면 정적(static) 멤버로 만들어야 한다.
    static : 해당 클래스의 모든 객체에 대해 하나의 데이터만 존재
    class GamePlayer {
    private:
        static const int NumTurns=5;	// 선언 O 정의 X, 선언은 헤더 파일에 정의는 구현 파일에
        int scores[NumTurns];
    }

※구식 컴파일러 대응법은 추후 작성 예정

결론: 상수를 만들려면 #define보다 const 객체나 enum을 우선 생각하자!


사례2: 매크로 함수

#define CALL_WITH_MAX(a, b) f((a)>(b)?(a):(b))	// 매크로는 인자마다 반드시 괄호 필요

int a=5, b=0;
CALL_WITH_MAX(++a, b);	// a가 2번 증가
CALL_WITH_MAX(++a, b+10);	// a가 1번 증가

인자마다 괄호를 씌워야 하며 위와 같은 괴현상을 만날 수 있다.

해결법

template<typename T>
inline void callWithMax(const T& a, const T& b)
{
	f(a>b ? a:b);
}

인자에 괄호를 씌우지 않아도 되며, 인자를 여러 번 평가할지도 모른다는 걱정도 없다.
또한 매크로가 아니므로 유효 범위와 접근 규칙을 그대로 따라간다.

결론: 함수처럼 쓰이는 매크로를 만들려면 #define 보다 인라인 함수를 우선 생각하자!

0개의 댓글