ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Effective C++] 2. #define을 쓰려거든 const enum, inline을 떠올리자.
    C_C++ 프로그래밍/Effective C++ 2019. 8. 28. 00:27

     

         로재의 개발 일기      

    #define #include #ifdef #ifndef

    #include 는 현재 프로그래밍에서는 대체할 수는 있는 수단이 없고

    #ifdef #ifndef은 매우 유용하게 사용하는 수단입니다.


    하지만, #define은 const, enum, inline 등등 매우 유용하게 쓰일 수 있는 수단이 있습니다.


    즉 선행 처리자보다 컴파일러를 가까이 하자는 의미인데요.

    예를 들자면 #define PI = 3.14라고 한다면

    선행 처리자가 PI라고 작성된 소스코드를 모두 3.14로 선행 처리가 됩니다.


    만약 이 부분에서 컴파일 오류나 논리 오류가 발생한다면?

    3.14라는 상수에서 오류가 검출이 되고 찾기 어렵겠죠?

    심지어 private 성격을 가지는 #define은 없습니다.



      const를 사용하자

    #define PI 3.14 대신에

    const double PI 3.14 를 사용해봅시다.


    매크로 같은 경우는 코드에 PI가 등장하기만 하면 선행 처리자에 의해 3.14로 모두 바뀌면서 결국 목적 코드 안에 3.14의 사본이 등장 횟수 만큼 들어가게 됩니다.

    하지만, const를 사용하게 되면 아무리 여러 번 쓰이더라도 사본은 딱 한 개만 생기게 됩니다.


    주의할 점으로는 상수 포인터를 사용할 때 입니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include<iostream>
     
    // #define -> const
    const char* const userName = "rojae";
    const std::string txt("hihi");
     
    int main(){
            std::cout << "UserName :" << userName << '\n'
                    << "Message :" << txt << '\n';
            return 0;
    }
     
    cs


      char* const userName = "rojae" 일 경우

     const char* const userName = "rojae"로 바꾸어 주면 됩니다.


    하지만 C++에서는 char 형 문자열보다는 std::string을 쓰기 때문에

    (구닥다리는 버립시다)

    다음과 같이 정의하는 것이 이롭습니다.


    const std::string userName("rojae")



      클래스 내부에 상수 선언

    클래스 내부 상수를 선언하는 경우에는 static을 사용하여

    캡슐화도 만족하게 되며 번거롭게 메모리가 복사되는 일은 없게 됩니다.


    책보고 대충 작성했는데...

    올바르게 한지는 모르겠네요.


     player.hpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    #include<vector>
    #include<iostream>
     
    class Player{
            private:
                    static const int maxUser = 10;
                    std::vector<int> score;
            public:
                    void insertScore(int &v){
                        if(score.size() > maxUser-1){
                                std::cout << "Max player" << '\n';
                                return;
                        }
                        score.push_back(v);
                    }
                    void getAllScore(){
                            std::cout << "Current Player :"
                                    << score.size() << '\n';
                            for(int i = 0; i < score.size(); i++){
                                    std::cout << score[i] << '\n';
                            }
                    }
    };
     
    cs


    player.cpp

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    #include <iostream>
    #include "player.hpp"
     
    int main(){
            int n;
            std::cout << "how many player?" << '\n';
            std::cin >> n;
     
            Player player;
     
            for(int i = 0; i < n; i++){
                    std::cout << "Insert Player scores :" << '\n';
                    int score;
                    std::cin >> score;
                    player.insertScore(score);
            }
            player.getAllScore();
     
            return 0;
    }
     
    cs

    # 컴파일러마다 문법이 먹히지 않는 경우가 있는데 그런 경우에는 다음과 같이 분리합니다.

    static const int maxUser;                    // 선언 헤더 파일

    const int player::maxUser = 10;        // 구현 파일



      enum을 사용한 enum hack

    사실 나열자 둔갑술이 제일 좋다고 합니다.

    위의 헤더파일의 maxUser 부분을

    다음과 같이 바꾸어 줍니다.

    1
       enum {maxUser = 10};
    cs

    이 경우 주소 값도 가지지 않으며 참조자를 가지지 않습니다.



      함수형 매크로를 사용할 때는 inline을 들이대자

    1
    #define CALL_WITH_MAX(a,b) f((a) > (b) ? (a) : (b))
    cs

    위와 같은 매크로를 자주 경험해봤을 것입니다.


    다음 소스코드를 봅시다.

    1
    2
    3
    4
    int a = 5, b = 0;
    CALL_WITH_MAX(++a, b);
    CALL_WITH_MAX(++a, b+10);
     
    cs

    실행해보면 놀랍지만

    두번째 줄에서 a는 2가 증가하며
    세번째 줄에서는 a가 1이 증가하게 됩니다.


    이를 해결하기 위해서 우리는 템플릿 inline 함수를 사용합니다.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    #include<iostream>
     
    template<typename T> inline T callWithMax(const T& a, const T& b);
     
     
    int main(){
            int a = 5, b = 0;
            std::cout << "Max :" << callWithMax(a,b) << '\n';
            std::cout << "Max :" << callWithMax(5.10.1<< '\n';
            std::cout << a << b;
            return 0;
    }
     
    template<typename T> inline T callWithMax(const T& a, const T& b){
        return (a > b)? a : b;
    }
     
    cs

    심지어 형 변환도 자유롭네요.


    마무리


    한번 봐가지고는 모르겠다.

    ※ 본 글은 개인 포트폴리오 혹은 공부용으로 사용하기 때문에, 무단 복사 유포는 금지하지만, 개인 공부 용도로는 얼마든지 사용하셔도 좋습니다



    반응형
Designed by Tistory.