Post

[ STUDY/Effective C++ ] 2022. 6. 18. 01:48

#define 소스코드의 경우에는 컴파일러에게 넘어가기 전, 선행처리자에서 숫자 상수로 바꾸어버린다.

그래서 #define pie 3.141 이라면

pie라는 이름은 컴파일러가 쓰는 기호 테이블에 들어가지 않고 숫자 상수(3.141)로 대체된다.

 

CONST

하지만 #define대신에 const를 사용해

const double pie = 3.141; 을 작성한다면 상수타입의 데이터이기 때문에 컴파일러에서도 보이게된다. 

 

그리고 매크로인 #define을 쓰게된다면 3.141의 사본이 등장횟수만큼 코드안에 들어가지만, 상수 타입인 const를 쓰면 사본이 한개만 생성되어 최종 코드의 파일 크기가 더작아지게된다. 

 

 

※ #define을 상수로 교체할때의 주의할 점

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

포인터는 꼭 const로 선언, 포인터가 가리키는 대상까지 const로 선언

const char * const alphabet = "ABCD";
const std::string alphabet = "ABCD";//위보다 더 좋은방법

 

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

Class GamePlayer{
private:
	static const int  NumTurns = 5; // 상수선언
	int scores[NumTurns];
	...
};

3번째 줄의 코드는 '정의'가 아닌 선언이다. 정적 멤버로 만들어지는 정수류 타입의 클래스 내부 상수는 정의 없이 선언만 해도 아무 문제없다.

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

하지만 컴파일러가 정의를 달라고 떼쓰는 경우에는 위와 같은 클래스 상수 정의를 '구현파일'에 둔다.

선언된 시점에서 상수의 초기값이 주어지기때문에, 정의에서는 초기값이 주어지면 안된다.

 

#define으로는 클래스 상수를 정의할 수도, 캡슐화 혜택도 받을 수 없다.

 

class CostEstimate{
private:
	static const double FudgeFactor; //정적 클래스 상수 선언(헤더파일에 두기)
	...
};
const double
	CostEstimate::FudgeFactor = 1.35; //정적 클래스 상수 정의(구현파일에 두기)

오래된 컴파일러의 경우에는 반대로 선언된 시점에서 초기값을 주는게 아닌, 정의 시점에 초기값을 주도록해야한다.

 

 

ENUM

여기서 예외)

Class GamePlayer {
private:
	enum {NumTurns = 5 }; //5에대한 기호식 이름으로 만듬
    
    int scores[NumTurns];
    ...
};

오래된 컴파일러를 배려해서 '나열자 둔갑술'(enum hack) 기법을 활용하자.

나열자 타입의 값은 int가 놓일 곳에도 쓸 수 있다. 원래라면 클래스내 초기화 금지로인해 위의 int scores[NumTurns]같은 배열멤버선언은 오래된 컴파일러에서 동작하지못한다.

 

 

INLINE

#define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b)) //#define을 쓴 경우


template<typename T> //inline에 대한 Template을 쓴 경우
inline void callWithMax(const T& a, const T& b)
{
	f(a>b ? a:b);
}
CALL_WITH_MAX(++a,b);
CALL_WITH_MAX(++a,b+10);

매크로를 작성할 때는 매크로 본문에 들어 있는 인자마다 반드시 괄호를 씌워주어야한다.

하지만 inline을 쓴다면 그런 괄호들을 굳이 씌울 필요가 없다.

 

이런 눈에 보이는 부분들이 아니더라도

밑의 코드들을 보았을때 #define매크로를 사용한다면 f가 호출되기도 전에 a가 증가하는 횟수가 달라지게 된다. 

하지만 inline을 쓴다면 인자를 여러번 평가할지 모른다는 걱정도 없다.

그리고 매크로가 아닌 진짜 함수이기때문에 함수의 유효범위 및 접근규칙을 그대로 따라가기에 기존 매크로의 효율유지는 와 함께 함수의 모든 동작방식 및 타입의 안정성까지 챙길 수 있다.

 

 

 

 

▲ top