휘발성과 가변성의 차이점에 대한 질문이 있습니다. 두 가지 모두 변경 될 수 있음을 의미합니다. 또 뭐야? 그들은 같은 것입니까? 차이점이 뭐야? 어디에 적용 할 수 있습니까? 두 가지 아이디어가 제안 된 이유는 무엇입니까? 다른 방법으로 사용하는 방법?
감사합니다.
답변:
mutable
필드에도 통해 액세스 개체 변경 될 수 const
포인터 또는 레퍼런스, 또는의 const
컴파일러 R / O 메모리에이를 은닉하지 알고 있으므로, 물체. volatile
컴파일러는 값이 "가능성이없는 수 있다는 잘못된 가정하에 그 값의 최적화 예를 들어 등록 할당을하지 인식 할 수 있도록 위치, 컴파일러 (예 : 일부 커널 레벨 드라이버)에 대해 알고하지 않는 코드에 의해 변경 될 수 있습니다 하나입니다 변경됨 "이 해당 레지스터에 마지막으로로드 되었기 때문입니다. 매우 다른 종류의 잘못된 최적화를 중지하기 위해 매우 다른 종류의 정보가 컴파일러에 제공됩니다.
volatile
객체가 컴파일러의 지식 밖에서 변경 될 수 있음을 의미 할뿐만 아니라 해당 쓰기가 쓸모없는 것처럼 보이더라도 컴파일러가 객체에 대한 쓰기를 제거 할 수 없음을 의미합니다. 예 : x = 1; x = 0;
ifx
휘발성 컴파일러 (하드웨어 수준에서 중요 할 수 있음) 모두 쓰기 작업을 방출한다. 그러나 비 휘발성 객체의 경우 컴파일러는 사용되지 않았으므로 작성하는 데 신경 쓰지 않도록 선택할 수 1
있습니다.
const
및 volatile
! 개체를 변경할 수는 없지만 등 뒤에서 변경할 수 있습니다.
mutable
: mutable 키워드는 둘러싸는 const 문을 재정의합니다. const 객체의 변경 가능한 멤버는 수정할 수 있습니다.
volatile
: volatile 키워드는 컴파일러가 해당 변수를 최적화하지 못하도록하는 변수를 선언 할 때 사용되는 구현 종속 수정 자입니다. Volatile은 컴파일러가 수행 할 수있는 최적화와 충돌 할 수있는 예기치 않은 방식으로 (즉, 인터럽트를 통해) 값이 변경 될 수있는 변수와 함께 사용해야합니다.
Volatile should be used with variables whose value can change in unexpected ways
우리가 무작위로를 사용하는 것을 선호 하는가?
그들은 확실히 같은 것이 아닙니다. Mutable은 const와 상호 작용합니다. const 포인터가 있으면 일반적으로 멤버를 변경할 수 없습니다. Mutable은 해당 규칙에 예외를 제공합니다.
반면에 휘발성은 프로그램의 변경 사항과는 전혀 관련이 없습니다. 이는 메모리가 컴파일러의 제어를 벗어난 이유로 변경 될 수 있으므로 컴파일러는 매번 메모리 주소를 읽거나 써야하며 레지스터에 콘텐츠를 캐시 할 수 없음을 의미합니다.
T
와서 a에 저장 const T*
하고 읽을 수 있습니다. 해당 객체를 만들면 쓰기를 시도하지 않더라도 volatile
주소를에 저장할 const T*
수 없습니다. volatile
프로그램 코드의 변경 / 수정 / 메모리 쓰기는 완전히 직교합니다.
차이를 조잡하지만 효과적으로 생각하는 방법은 다음과 같습니다.
volatile
bytes_received, mutable
reference_count.
volatile은 멀티 스레딩 애플리케이션을 다룰 때도 매우 유용합니다. 즉, 메인 스레드 (main ()이있는 곳)가 있고 변수 "app_running"이 참인 동안 계속 회전하는 작업자 스레드를 생성합니다. main ()은 "app_running"이 참인지 거짓인지를 제어하므로 "app_running"선언에 volatile 속성을 추가하지 않으면 컴파일러가 보조 스레드가 실행하는 코드에서 "app_running"에 대한 액세스를 최적화하면 main ( )는 "app_running"을 false로 변경할 수 있지만 값이 캐시되었으므로 보조 스레드는 계속 실행됩니다. Linux 및 VisualC ++에서 gcc를 사용하여 동일한 동작을 보았습니다. "app_running"선언에있는 "volatile"속성이 문제를 해결했습니다. 그래서,
volatile
객체는 CPU를 전혀 사용하지 않는 프로세스에 의해 변경 될 수도 있습니다. 예를 들어, 통신 주변 장치의 바이트 수신 레지스터는 바이트 수신시 자체적으로 증가 할 수 있으며 이는 인터럽트를 트리거 할 수도 있습니다. 또 다른 예는 주변 장치에서 보류중인 인터럽트 플래그 레지스터입니다.