const vs mutable

진리는어디에 2006. 12. 21. 18:40
const vs mutable

일반 변수들을 컴파일 타임에 상수화 시켜 버리는 키워드가 있다. 그 이름은 바로 const!!
const의 힘은 참으로도 강해서 const로 선언된 변수의 값을 바꾸고자 하는 시도가 있으면 바꾸면 안된다고 아주 지랄을 한다. 또한 엄연히 스코프룰과 타입룰을 따르고 있기에 혹시나 발생 할 가능성이 있는 실수들을 사전에 방지 할 수 있다. 그래서 요즘은 #define 등 상수가 필요한 경우 const로 대체 하는 추세다.
이런 const의 사용법을 간단히 알아 보도록 하자.

* const 변수 선언

1. 일반 변수 선언 :
char str[] = "Babo";
char* jinmo = str;
  아무런 제약이 없는 문자열의 선언이다. 포인터를 변경할 수도 있고, 포인터가 가리키고 있는 값 역시 변경이 가능하다.

2. 비상수 포인터, 상수 데이터
const char* jinmo = str;
char const *jinmo = str;
  const 키워드가 '*'의 왼쪽에 위치한다. 첫번째나 두번째나 같은 의미를 지니고 있다. 이해 하기 쉽게 하려면 *jinmo를 가리키는 const라고 생각하라. char는 무시해도 된다.

3. 상수 포인터, 비상수 데이터
char* const jinmo = str;
const 키워드가 '*'의 오른쪽에 위치한다. const jinmo 라고 생각하라. 여기서 jinmo라는 변수는 포인터를 가리키고 있는 변수다. 결국 포인터가 상수화 되고, 데이터는 아무런 관련이 없어진다는 이야기다.

4. 상수 포인터, 상수 데이터
const char* const jinmo = str;
이런식으로 const 키워드가 양쪽으로 붙게 되면 포인터이든, 포인터가 가리키고 있는 값이든 둘다 바뀔수가 없다는 뜻이다.(이로써 진모는 확실히 어쩔수 없는 바보가 되었다)

* 함수에서의 const 사용

1. 리턴값의 상수화
class TextBlock {
  public :
        ...
        const char& operator[](std::size_t position) const {
            return m_text[position];
        }
        char& operator[](std::size_t position) {
            return m_text[position];
        }
  private :
        std::string m_text;
}
출처 : Effective C++
위의 예제를 보도록 하자. 일단 가장 눈에 먼저 들어오는 것은 같은 이름, 같은 파라메터함수의 오버로딩이다. 하지만 const 함수와 비 const 함수 사이에는 이런식으로 오버라이딩이 가능하다고 한다.
  그리고 호출 될때의 구분은 아래와 같이 대입 되는 변수가 const인지 아닌지에 따라 구분 된다.
void print(const TextBlock& ctb) {
  std::cout << ctb[0];
}

void print(TextBlock& tb) {
  std::cout << tb[0];
}
  리턴값을 const로 하는 가장큰 이유는 참조자 리턴 때문이다. 일반 변수를 복사하여 리턴하게 된다면 클래스 내부의 멤버변수(혹은 함수를 통해 리턴되는 전역변수)의 값을 변화 시킬 수 있는 방법은 없다. 하지만 참조자를 리턴하게 된다면 원래의 값에 접근할 수 있는 방법이 생기게 되고, 이를 이용해 자신의 의도와는 상관없이 값을 바꾸는 경우가 발생할 수 있다(원래 원했던 의도라고 한다면 할 말이 없다).
  이런 경우 const키워드를 이용해 참조자를 리턴하게 된다면 리턴된 값을 바꾸려는 시도를 애초에 원천적으로 차단할 수 있다.

2. 함수의 상수화

  함수의 선언 뒤에 const 키워드가 붙는 것을 볼수 있다.
const char& operator[](std::size_t position) const {
     return m_text[position];
}
  이것은 함수의 정의가 const가 된다는 뜻으로 함수 내에서 read 연산(출력 같은 것들)은 가능하지만, write 연산('='같은 대입 연산)은 허용되지 않는다. const가 붙은 함수 안에서는 절대적으로 모든 값들이 자신의 값 그대로를 유지한다는 보장을 해 줄 수 있다.

이야기를 여기까지 끌고 왔는데 제일 처음 제목으로 나왔던 mutable이라는 것에 대해서는 아직까지 한번도 언급이 없었다. 지금까지 const의 기능에 대해 이야기 했다면 이제 부터는 mutable에 대해서 이야기 하겠다.

거창하게 이야기 했지만 mutable은 내가 알고있는 한은 그렇게 대단한것이 아니다. 다만 const를 무효화 시킬수 있는 키워드 정도라고 설명 하겠다. 위에서 const 키워드가 붙은 함수 내에서는 어떤 변수에게도 write 연산을 할 수 없다고 했었다. 하지만 mutable로 선언하게 된다면 이야기가 달라진다.
위의 예제에 [] 연산자 오버로딩으로 char 참조자를 리턴하도록 되어있는 const함수에 가장 최근에 리턴된 문자가 무엇인지 기록할수 있는 기능을 추가 해보도록 하자.
 
class TextBlock {
  public :
        ...
        const char& operator[](std::size_t position) const {
            m_recentReturnVal = m_text[position];
            return m_recentReturnVal;
        }
        char& operator[](std::size_t position) {
            return m_text[position];
        }
  private :
        std::string m_text;
        char m_recentReturnVal;  
};
붉은 색으로 되어있는 부분이 에러다. 컴파일이 되지 않는다. const로 선언된 함수 내에서 왜 wirte 연산을 하려 하냐고 컴파일러가 따진다. 똑똑한놈이다. 모르게 했는데 어느새 눈치 채고 바락바락 악을 쓴다.
하지만 mutable이라는 키워드를 쓴다면 이런것 쯤이야 말끔히 날려 버릴 수 있다.
class TextBlock {
  public :
        ...
        const char& operator[](std::size_t position) const {
            m_recentReturnVal = m_text[position];
            return m_recentReturnVal;
        }
        char& operator[](std::size_t position) {
            return m_text[position];
        }
  private :
        std::string m_text;
        mutable char m_recentReturnVal;  
};
위와 같이 학 된다면 컴파일러의 불평을 말끔히 날려 버릴수 있다.

하지만 어떤 경우에 mutable을 써야 하는가? 이렇게 const라고 엄연히 규칙을 정해 놓고 mutable로 그 규칙을 마음대로 위반한다면 const 함수라는 이름 자체가 무색해져 버린다. 여기서 답을 주면 좋겠지만..솔찍히 언제 어떻게 써야 하는지는 나도 잘 모른다. 그냥 그때 그때 대충 상황에 맞게 쓰면 되는것 같다.

'진리는어디에' 카테고리의 다른 글

TIME_WAIT state vs SO_REUSEADDR option  (4) 2007.01.08
Edge trigger vs Level trigger  (2) 2007.01.05
const vs mutable  (4) 2006.12.21
PHP - 문자열 취급하기  (0) 2006.12.14
가변인자를 이용한 함수(va_list)  (10) 2006.12.13
SQL command  (0) 2006.12.13
Posted by kukuta
TAG

댓글을 달아 주세요

  1. Favicon of http://blog.ggamsso.wo.tc/ BlogIcon 깜쏘 2006.12.21 20:40  댓글주소  수정/삭제  댓글쓰기

    const가 필요해서 쓴건데 mutable를 쓴다는 건 설계 자체가 잘못 된거죠.
    저런 키워드는 머리속에서 지워야 합니다.

    Effective C++에서 보면 제일 흥미를 끌었던 것이 캐스팅 표기 방법...
    눈에 확 들어오는게 -_-;;
    하지만 쓰기 귀찮아서 안 쓰고 있죠.
    확실히 스콧 마이어씨가 쓴 책은 읽을 거리가 많습니다.
    하지만 그 만큼 백그라운드가 받쳐줘야 한다는 단점도 있지만...

    암튼 단순 코더에서 프로그래머로 실력을 올려주는 좋은 책임은 틀림 없죠.

    • Favicon of https://kukuta.tistory.com BlogIcon kukuta 2006.12.24 17:13 신고  댓글주소  수정/삭제

      아무리 상속에서 private가 모든 것을 막아 준다고는 하지만 c++에는 그것을 무력화 시킬수 있는 friend가 있잖아..
      mutable도 비슷한거라고 생각한다. 제약을 걸긴하지만 조금씩 옆길로 새나갈수 있는 여유로움..

      그것이 바로 C++의 매력이 아닐까 싶다

  2. Favicon of http://pudae.net BlogIcon pudae 2006.12.24 22:42  댓글주소  수정/삭제  댓글쓰기

    const char* cnost jinmo = str;
    오타가 있으므로 아직은 희망이..후후후
    mutable이 필요한 경우는 의미상 const 이지만 실제로는 const가 아닌 경우임..
    언제나 그렇듯 알아서 상상하시길..후후후

    • Favicon of https://kukuta.tistory.com BlogIcon kukuta 2006.12.26 11:12 신고  댓글주소  수정/삭제

      앗!! 이런 왜 하필이면 이런데서 오타가...
      곧 수정하도록 하마...ㅋㅋ

      우리 pudae씨는 const한 string value를 가지고있어야지..ㅋㅋ