ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • ch01. 가급적 선행 처리자 보다 컴파일러를 활용하자.
    effective c++ & c++ 2022. 8. 25. 19:43

    #define ASPECT_RATIO 1.653

    ASPECT_RATIO라는 기호식 이름은 컴파일러에게 넘어가기 전에 선행 처리자(Pre Processor)가 밀어버리고 숫자 상수로 바꾸어 버리기 때문에 ASPECT_RATIO라는 이름은 컴파일러의 기호 테이블에 들어가지 않는다.

     

    따라서 숫자 상수로 대체된 코드에서 컴파일 에러가 나면 파악이 어려워지기 때문에,

    const double AspectRatio = 1.653;

    과 같이 상수를 사용해 주는 것이 좋다.

     

    상수로 쓰게 되면,

     

    1. 변수명이 컴파일러의 기호 테이블에 입력된다.

    2. 상수가 부동 소수점 실수 타입일 경우, 컴파일을 거친 최종 코드의 크기가 #define을 썼을 때보다 작게 나올 수 있다.

    -> #define으로 선언하게 되면 ASPECT_RATIO가 나오는 곳마다 1.653으로 바뀌면서 사본을 생성하지만, 상수로 정의할 경우 사본은 한 번만 생성되기 때문이다.

    3. 유효범위를 지정할 수 있다. -> 캡슐화 가능.

     

     

    #define으로 선언된 것을 상수로 교체하기 위해 주의해야할 점.

     

    1. 상수 포인터를 정의하는 경우, 포인터와 포인터가 가르키는 대상 모두에 const를 붙여준다.

    예) const char* const authorName = "Scott Meyers"; -> const std::string authorName("Scott Meyers");

     

    2. 클래스 상수를 선언할 경우, 상수의 사본 개수가 1개를 넘지 못하게 하기 위해 static 멤버로 정의해준다.

    예)

    class GamePlayer
    
    {
        private:
    
            static const int NumTurns = 5; //선언. 정의된 것이 아님에 주의
    
    }
    
    const int GamePlayer::NumTurns; //정의

     

     

    ** static const 멤버변수는 클래스가 정의될 때, 지정된 값이 유지되는 상수이기 때문에,

    선언과 동시에 초기화가 가능하도록 문법에서 정의하고 있다.

     

    ** static 멤버로 만들어지는 정수류 타입의 클래스 내부 상수(const)는 이에 대한 주소를 취하지 않는 한, 선언만 해줘도 문제가 없다. -> 주소를 취하거나 컴파일러에 따라 정의를 요구하는 경우, 정의를 적어줘야 함.

     

    ** 클래스 상수는 선언 시점에서 초기값이 주어지기 때문에 정의에는 초기값이 있으면 안된다.

    -> 컴파일러에 따라 선언에서 초기화를 허용하지 않는 경우, 정의 시점에 초기값을 준다.

     

     

    "나열자 둔갑술"

    정적 클래스 상수에 대해 선언과 동시에 초기화를 금지하는 컴파일러의 경우, 

    정적 클래스 상수를 배열의 크기로 활용하여 멤버를 선언할 수 없다.

    이를 해소하기 위한 방법으로 "나열자 둔갑술"을 사용할 수 있다.

     

    예)

    class ConstEstimate
    
    {
    
        private:
    
            static const int idx;
    
            int score[idx]; //불가능
    
    }
    
    const int ::ConstEstimate idx=5;

     

    class GamePlayer
    
    {
    
        private:
    
            enum { NumTurns = 5 } ; //나열자 둔갑술
    
            int score[NumTurns] ; //가능
    
    }

     

    - #define과 유사한 방식이며 enum의 주소를 취할 수 없다.

    - 어떤 형태의 쓸데없는 메모리 할당을 저지르지 않는다.

     

     

    #define을 활용한 매크로 함수는 인라인 함수에 대한 템플릿으로 대체하자.

     

    - 유효범위 및 접근 규칙을 확인할 수 없기 때문이다.

     

    #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);
    }

     

Designed by Tistory.