const 멤버 함수와 mutable 키워드
const 멤버 함수는 함수 내에서 const 변수뿐만 아니라, 일반 변수의 값도 바꿀 수 없도록 제한을 건 클래스 멤버 함수입니다.
그리고, const 멤버 함수 내에서는 멤버 변수의 수정을 막기 위해 일반 멤버 함수도 사용할 수 없습니다.
const 멤버 함수에 관한 내용은 여기에서 볼 수 있습니다.
하지만, 경우에 따라 멤버 변수의 값을 변경하는 것이 필요한 때가 있습니다.
그때 사용할 수 있는 키워드가 mutable입니다.
mutable 키워드는 클래스의 데이터 멤버에 적용할 수 있는 키워드입니다.
이때, 데이터 멤버는 비정적( non-static ), 비참조( non-reference )이어야 하며, const 멤버 변수가 아니어야 합니다.
이렇게 mutable이 붙은 멤버 변수는 const 멤버 함수 내에서 값을 변경할 수 있습니다.
다음 예제는 mutable 키워드의 사용법을 보여줍니다.
class StateObj
{
int m_flags;
mutable int m_accessCount; // mutable 변수
public:
int GetFlag() const
{
m_accessCount++; // 객체에 접근한 횟수를 기록
return m_flags;
}
};
위의 GetFlag 함수는 const 멤버 함수입니다.
그렇지만, mutable 키워드를 사용해서 m_accessCount 멤버 변수의 값을 변경할 수 있습니다.
예를 하나 더 들어보겠습니다.
이 예제는 100,000개의 원소를 가진 vector의 합을 구하고, 재사용을 위해 그 값을 mutable 변수에 저장합니다.
이렇게 저장된 값은 데이터가 변경되어 재계산이 필요할 때 갱신하게 됩니다.
#include <vector>
#define SIZE 100000
class ComputeObj
{
mutable bool m_bModified; // mutable
mutable int m_nComputedValue;
std::vector<int> m_Buffer;
public:
ComputeObj() : m_Buffer(SIZE, 10){}
int ComputeSum() const { // const 멤버 함수
if ( !m_bModified)
return m_nComputedValue; // 저장된 값
int sum = 0;
for( int x : m_Buffer){
sum += x;
}
m_bModified = false;
m_nComputedValue = sum; // 계산값을 저장
return sum;
}
void ChangeValue(int idx, int val){
m_Buffer[idx] = val;
m_bModified = true;
}
};
람다 표현식( lamda expression )과 mutable 키워드
mutable은 람다 표현식( lamda expression )에도 사용할 수 있습니다.
람다 표현식에 관한 내용은 여기에 정리해 두었습니다.
람다는 외부의 변수를 수용( capture )할 때, 값( call by value ) 또는 참조 ( call by reference )의 형식으로 캡처( capture )할 수 있습니다.
만약, 외부의 변수를 값으로 캡처하면, 외부의 변수는 const 속성을 띠는데,
필요한 경우 mutable 키워드를 사용하여 const 속성을 제거할 수 있습니다.
int main(){
vector<int> vec = { 1, 2, 3, 4, 5 };
int sum = 0;
for_each( vec.begin(), vec.end(), [sum](int val) mutable {
sum += val; // sum의 const 속성이 없어짐
cout << sum;
});
return 0;
}
위의 예제에서, sum 변수를 값으로 capture 하면 const 속성을 갖게 됩니다.
하지만, 이 const 속성을 mutable 키워드를 사용하여 제거하였습니다.
그래서, sum의 값을 변경할 수 있습니다.
하지만, 변수 sum 값으로 캡처했기 때문에, 외부의 sum의 값은 변경되지 않습니다.
'C, C++ > C++ 언어' 카테고리의 다른 글
[C++] noexcept 키워드를 사용하는 이유 (0) | 2024.08.01 |
---|---|
[C++] namespace가 필요한 이유 (0) | 2024.07.30 |
[C++] 람다 표현식( lamda expression )에 대한 설명 (1) | 2024.07.26 |
[C++] explicit 키워드와 변환 생성자( converting constructor ) (0) | 2024.07.24 |
[C++] 별명을 만드는 typedef와 using (0) | 2024.07.22 |