**const**는 컴파일러에게 변수가 변경 불가능하다는 것을 알리며(초기화 후 변경될 수 없음), 상수 변수를 선언하거나 객체의 상태를 변경하지 않는 메서드를 보장하는 데 사용됩니다.
**mutable**은 const 메서드 내에서도 클래스 필드의 값을 변경할 수 있게 해줍니다.
**volatile**은 변수의 값이 프로그램의 제어 밖, 예를 들어 하드웨어에 의해 변경될 수 있음을 컴파일러에게 알리며, 컴파일러는 이에 대한 접근을 최적화해서는 안 됩니다.
class Logger { public: void log() const { ++count; // 허용됨 — count는 mutable로 선언됨 } private: mutable int count = 0; }; volatile int flag; void wait() { while (flag == 0) { /* 컴파일러는 flag가 volatile이기 때문에 루프를 최적화하지 않음 */ } }
«클래스의 멤버를 동시에
const와mutable로 선언하면 어떻게 됩니까?»
답변: 그렇게 할 수 없습니다. 이는 상충하는 한정자이며, 컴파일러는 오류를 발생시킵니다.
이야기
하드웨어와 작업하기 위한 산업 소프트웨어에서 개발자는 외부 인터럽트로 업데이트되는 데이터를 일반 int로 선언했습니다. 컴파일러의 최적화는 이러한 변수의 반복적인 읽기를 제거했으며, 그로 인해 프로그램이 무한 루프에 빠졌습니다. 문제는
volatile int로 변경한 후에야 진단할 수 있었습니다.
이야기
로깅 클래스 중 하나는 호출 횟수를 업데이트하는
log() const메서드가 있었습니다. 처음에는const_cast포인터를 통해 이를 수행했으나, 많은 경고와 불분명한 버그가 발생했습니다. 문제는 카운터를mutable을 통해 정확하게 선언한 후에 사라졌습니다.
이야기
클래스의 몇 가지 메서드는
const로 선언되었지만, 포인터 타입의 멤버는 변경되었습니다(예: 캐시 구현을 위해). 이는 "const-correctness" 논리를 위반하게 되었고, 객체가 실제로 읽기 전용 영역에 배치되었을 경우 UB(미정의 동작)를 초래했습니다.mutable을 사용하거나 디자인을 변경해야 했습니다.