[Effective C++] #2_#define 사용의 대안
Scott Meyers의 "Effective C++"를 통해, C++ 구현에 필요한 개념들을 이해하고, 기록하기 위함입니다. 해당 항목은 1장 'C++ 기본', 항목 2 "#define을 쓰려거든, const, enum, inline을 떠올리자"에 해당하는 내용입니다.
1. #define, 매크로 <-> const, 상수
#define ASPECT_RATIO 1.653
const double AspectRatio = 1.653;
"#define" 사용의 경우 소스코드가 컴파일러에게 넘어가기 전, 선행 처리자가 "이름"을 밀어버리고, 숫자 상수로 바꾸어버립니다. 결과적으로, "ASPECT_RATIO"는 컴파일러가 사용하는 기호 테이블에 들어가지 않습니다. 숫자 상수로 대체된 소스코드는 컴파일 에러 발생 시 여러 가지 문제를 야기합니다. 에러 메시지를 확인하면, ASPECT_RATIO가 아니라, 1.653으로 표기될 테니까요. 소스코드 작성 과정에서 사용자가 직접 작성한 매크로의 경우, 1.653은 "ASPECT_RATIO"를 대체하는 매크로라는 것을 알고 있을 겁니다. 컴파일 에러가 발생해도 크게 문제 될 건 없어 보입니다. 하지만, 매크로가 작성된 소스코드를 사용자가 직접 작성한 것이 아니라면, 1.653의 출처를 아무도 알 수 없게 됩니다. 우리는 "#define"을 대신하여, 상수 사용을 고려해볼 겁니다. 상수로 정의된 "AspectRatio"는 컴파일러가 발견할 수 있고, 기호 테이블에도 포함됩니다. 더불어, "#define"을 사용하면, 소스코드 내부에 "ASPECT_RATIO"가 등장할 때마다 선행 처리자는 1.653의 사본을 생성할 것이고, 상수 타입의 "AspectRatio"의 사본은 딱 한 개만 생깁니다.
2. #define, 매크로 <-> enum, 열거형
class GamePlayer {
private:
...
enum { NumTurns = 5 };
int scores[NumTurns];
...
};
"enum", 즉 열거형의 동작방식은 "const"보다 "#define"에 더 가깝습니다. 왜냐하면, "const"의 주소를 취하는 것은 합당하지만, "enum"의 주소를 취하는 것은 불법입니다, "#define"의 경우는 당연하죠. 사용자가 선언한 상수 정수를 통해 주소를 얻거나, 참조자로 사용하는 것을 막기 위해 "enum"을 사용할 수 있겠습니다. 더불어 "const"와 비교했을 때, 쓸데없는 메모리 할당이 발생하지 않습니다!
3. #define 함수 <-> inline 함수
#define CALL_WITH_MAX (a, b) f((a) > (b) ? (a) : (b))
int a = 5, b = 0;
CALL_WITH_MAX(++a, b); // a가 두 번 증가
CALL_WITH_MAX(++a, b+10); // a가 한 번 증가
template<Typename T>
inline void callWithMax (const T& a, const T& b){
f(a > b ? a : b);
}
"#define"으로 정의된 함수를 예제를 통해 살펴보겠습니다. "f" 함수를 매크로 정의를 통해 CALL_WITH_MAX가 "f"를 대신하고 있습니다. 아래 사용 예제를 통해 #define 함수의 문제점을 발견 할 수 있습니다. ++a가 b보다 클 경우, a는 두 번 증가하고, a가 b보다 작을 경우 a는 한 번 증가하는 사태가 발생합니다. 우리는 #define으로 정의한 함수를 인라인 함수를 제공하는 템플릿을 고려해 볼 겁니다. "callWithMax"는 템플릿 함수로, 동일한 타입의 인자 두 개를 받아서 "f" 함수를 호출합니다. "#define" 함수처럼 함수 본문에 괄호를 여러 번 사용할 필요가 없고, 인자를 여러 번 평가하는 일이 발생하지도 않습니다. 또한 "callWithMax"는 실제 함수이기 때문에 유효 범위 및 접근 규칙이 정상적으로 적용됩니다.
단순 상수 사용의 경우 #define보다 const 혹은 enum을 우선시 하자. 매크로 함수는 사용전에 인라인 함수를 우선시 하자.
'언어 > Effective C++' 카테고리의 다른 글
[Effective C++] #4 객체의 초기화 (0) | 2022.01.06 |
---|---|
[Effective C++] #3_const 사용 (0) | 2022.01.05 |
[Effective C++] #33_오버라이딩 문제 (0) | 2022.01.03 |
[Effective C++] #32_public 상속 (0) | 2022.01.03 |
[Effective C++] #31_파일 사이의 컴파일 의존성 (0) | 2021.12.31 |