Why is this an issue?
The main intended use-case for volatile
in C and C++ is to access data that can be modified by something external to the program,
typically some hardware register. In contrast with other languages that provide a volatile
keyword, it does not provide any useful
guarantees related to atomicity, memory ordering, or inter-thread synchronization. It is only really needed for the kind of low-level code found in
kernels or embedded software, i.e. using memory-mapped I/O registers to manipulate hardware directly.
According to the C standard:
volatile
is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might
be changed by means undetectable by an implementation.
Only C11/C++11 "atomic types" are free from data races, and you should use them or synchronization primitives if you want to avoid race
conditions.
This rule raises an issue when a local variable or class data member is declared as volatile
(at the top level of the type, pointers
to volatile are not reported).
Noncompliant code example
volatile int counter; // Noncompliant
User * volatile vpUser; // Noncompliant; pointer is volatile
User volatile * pvUser; // Compliant; User instance is volatile, not the pointer
Compliant solution
atomic_int counter;
std::atomic<User*> vpUser;
User volatile * pvUser;
Resources