본문 바로가기
개발/C++

[EC++] #define 대신 const, enum, inline을 사용해야 하는 이유

by 램램이 2020. 2. 11.

이 글은 'Effective C++' 을 읽고 정리한 내용입니다.

 

 

"선행 처리자보다 컴파일러를 더 가까이하자."

 

#define

- #define은 소스코드가 어떻게든 컴파일러에게 넘어가기 전에 선행 처리자가 밀어버리고 '숫자 상수로' 바꾸어버린다.

 

문제점

- #define으로 정의된 코드에서 에러가 발생하게되면, ASPECT_RATIO가 아닌, 1.653으로 에러메세지가 발생하게 된다.

- 위와 같은 경우에는 코드에서 1.653이 의미하는 바가 무엇인지 모를 경우에 곤란한 상황이 생긴다.

 

const

위와같은 문제를 해결하는 방법으로 const를 이용하는 방법이 있다.

장점

- AspectRatio는 언어 차원에서 지원하는 상수 타입의 데이터이기 때문에 컴파일러에서 처리된다.

- 상수가 부동 소수점 실수 타입일 경우 #define을 썼을 때보다 작게 나올수있다.

그 이유는 #define으로 처리된 코드는 ASPECT_RATIO가 등장만하면 선행 처리자에 의해 1.653으로 바꾸기 때문에,

결국 사본이 등장 횟수만큼 들어가게 되지만, 상수타입의 AspectRatio는 여러번 쓰더라도 사본은 딱 한 개만 쓰인다.

 

#define을 상수(const)로 바꿀 때 주의할점

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

- 상수 pointer는 꼭 const로 선언해 주어야 하며, 추가로 포인터가 가리키는 대상까지 const로 선언하는 것이 보통이다.

( const pointer에 대한 추가 내용(바로가기) )

 

- cf) 문자열 상수를 쓸땐 char * 보단 string 객체가 대체적으로 사용하기 좋다.

 

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

-  클래스 멤버로 상수를 정의하는 경우, 그 상수의 사본 개수가 한 개를 넘지 못하게 하기 위해선 정적(static) 멤버로 만들어야한다.

- 위에있는 코드의 NumTurns는 '선언' 된것이다. '정의'가 아니다.

- 정적멤버로 만들어지는 정수류 타입은 정의가 없어도 컴파일러의 오류가 없다.

- 만약 컴파일러의 이상으로 정의가 필요하다고 하면 헤더파일이 아닌 구현 파일에 다음과 같은 정의를 제공 해야한다.

-  정의에는 상수의 초기값이 있으면 안된다. 클래스 상수의 초기값은 해당 상수가 선언된 시점에서 바로 주어지기 때문.

 

위 경우도 받아들여지지 않는 컴파일러가 있다 이럴 때는 초기값을 상수 '정의'시점에 주면된다.

 

나열자 둔갑술( enum hack )

- 이 책의 경우는 위에 말한 경우를 제외하고, 클래스를 컴파일하는 도중에 클래스 상수의 값이 필요할 때인데, 배열 멤버를 선언할 때의 경우, 배열의 크기를 알아야 한다며 정적 타입의 정적 클래스 상수에 대한 클래스 내 초기화를 금지하는 에러를 배출하는 경우 나열자 둔갑술을 사용하여 해결 할 수있다.

- 나열자 둔갑술의 동작 방식은 const 보단 #define에 가깝다.

- 선언한 정수 상수를 가지고 다른 사람이 주소를 얻는다든지 참조자를 쓴다든지 하는 것이 싫다면 enum을 사용하라.

- enum은 #define처럼 어떤 형태의 쓸데없는 메모리 할당을 저지르지 않는다.

- 상당히 많은 코드에서 이 기법이 사용 되고 있으므로 실용적인 이유에서 라도 눈에 익혀 놓는 것이 좋다.

 

 

inline 함수

- #define을 잘못 사용하는 것중 하나는 매크로 함수이다. 함수 처럼 보이지만 함수 호출 오버헤드를 일으키지 않는다.

- 위와 같은 매크로 정의는 많은 문제를 야기한다

- 이 문제를 해결하기 위해 인라인 함수에 대한 템플릿을 준비한다.

- 위 함수는 템플릿이기 때문에 동일 계열 함수군을 만들어 낸다.

- 동일한 타입의 객체 두 개를 인자로 받고, 둘중에 큰 것을 f에 넘겨서 호출하는 구조.

- callWithMax는 함수이기 때문에 유효범위 및 접근 규칙을 그대로 따라간다.

 

결론

- 단순히 상수를 쓸때는 #define보다 const객체나 enum을 우선 생각하자.

- 함수처럼 쓰이는 매크로를 만들려면 #define 매크로보다 인라인 함수를 먼저 생각하자.

댓글