C++ 끄적임

[ C++ ] Mutable

algohun 2024. 12. 2. 16:12

C++에서 mutable은 다소 생소한 키워드입니다.

mutable은 const 함수에서 특정 멤버 변수의 값을 변경할 수 있도록 허용합니다.

 

이번 글에서는 mutable의 동작과 필요성, 그리고 관련된 실험 결과를 다룹니다.

1. mutable 키워드란?

mutable은 const 함수에서 값 변경이 필요한 변수 앞에 사용하는 키워드입니다. 이를 통해 객체의 논리적 불변성을 유지하면서도 부수적인 상태 변경이 가능해집니다.

mutable의 사용 예시

다음은 로그 기록을 위한 간단한 예제입니다.

#include <iostream>
using namespace std;

class  Data {
public:
    Data() :logCount{}{}
    void PrintLog() const{
        ++logCount;
        cout << "[" << logCount << "]\n";
    }
private:
    mutable int logCount;
};

int main() 
{
    Data d;
    for (int i = 0; i < 10; ++i) {
        d.PrintLog();
    }
}
  • PrintLog는 const 함수로 선언되어 있습니다. 따라서 일반적인 멤버 변수는 수정이 불가능합니다.
  • 그러나, logCount는 mutable 키워드로 선언되어 있어 const 제한을 무시하고 수정할 수 있습니다.

2. 왜 mutable이 필요할까?

mutable의 필요성

mutable 키워드는 다음과 같은 상황에서 사용됩니다:

  1. 로그 기록: 로그 횟수 카운트 등 부수적인 상태 변경.
  2. 캐싱: 연산 결과를 저장하여 반복 계산 방지.
  3. 참조 횟수 관리: 스마트 포인터 등에서 사용.

이러한 작업들은 객체의 논리적 불변성(Logical Constness)에는 영향을 미치지 않지만, 물리적 상태(Physical State)를 변경해야 할 필요가 있습니다.


3. const 함수에서 값 변경이 제한되는 이유

const 함수에서 멤버 변수 수정이 제한되는 이유는 this 포인터의 동작에 있습니다.

this 포인터와 const

const 함수 내부에서는 this 포인터가 const ClassName* 타입으로 처리됩니다. 이는 다음을 의미합니다:

  • this는 변경 불가능한(const) 객체를 가리킨다고 간주됩니다.
  • 따라서, const 함수는 멤버 변수 값을 변경할 수 없습니다.

4. 실험: this의 타입 출력

this가 const로 처리된다는 것을 확인하기 위해 실험을 진행했습니다.

#include <iostream>
#include <type_traits>
#include <string>

class Example {
private:
    int value;
    mutable int mutableValue;
public:
    Example(int val) : value{val},mutableValue{val} {}

    void nonConstFunction() {
         std::cout << "nonConstFunction this type: "
                  << (std::is_const<std::remove_pointer<decltype(this)>::type>::value
                      ? "const"
                      : "non-const")
                  << std::endl;
    }

    void constFunction() const {
        std::cout << "constFunction this type: "
                  << (std::is_const<std::remove_pointer<decltype(this)>::type>::value
                      ? "const"
                      : "non-const")
                  << std::endl;
    }
};

int main() {
    Example ex(10);
    ex.nonConstFunction();
    ex.constFunction();
}

출력 결과

nonConstFunction this type: non-const 
constFunction this type: const

분석

  • nonConstFunction: this는 일반 객체를 가리키므로 non-const로 출력됩니다.
  • constFunction: this는 변경 불가능한 객체를 가리키므로 const로 출력됩니다.

5. mutable 변수의 타입은?

다음으로, mutable 변수의 타입을 확인하는 실험을 진행했습니다.

  void constFunction() const {
        std::cout << "constFunction this type: "
                  << (std::is_const<std::remove_pointer<decltype(mutableValue)>::type>::value
                      ? "const"
                      : "non-const")
                  << std::endl;
    }

결과는 non-const가 출력됐습니다.

 

mutable 변수는 const 함수 내부에서도 변경 가능한 상태로 처리되므로, non-const로 출력되었습니다.


6. 결론

  • mutable은 const 함수에서 특정 멤버 변수의 값을 변경 가능하게 만듭니다.
  • const 함수에서 멤버 변수 수정이 제한되는 이유는, this 포인터가 const 객체를 가리키는 포인터로 처리되기 때문입니다.
  • mutable은 로그 기록, 캐싱, 참조 횟수 관리 등 부수적 상태 변경이 필요한 상황에서 유용합니다.