volatile
QualifierThe precise meaning of volatile
is inherently machine dependent and can be understood only by reading the compiler documentation. Programs that use volatile
usually must be changed when they are moved to new machines or compilers.
Programs that deal directly with hardware often have data elements whose value is controlled by processes outside the direct control of the program itself. For example, a program might contain a variable updated by the system clock. An object should be declared volatile
when its value might be changed in ways outside the control or detection of the program. The volatile
keyword is a directive to the compiler that it should not perform optimizations on such objects.
The volatile
qualifier is used in much the same way as the const
qualifier. It is an additional modifier to a type:
volatile int display_register; // int value that might change
volatile Task *curr_task; // curr_task points to a volatile object
volatile int iax[max_size]; // each element in iax is volatile
volatile Screen bitmapBuf; // each member of bitmapBuf is volatile
There is no interaction between the const
and volatile
type qualifiers. A type can be both const
and volatile
, in which case it has the properties of both.
In the same way that a class may define const
member functions, it can also define member functions as volatile
. Only volatile
member functions may be called on volatile
objects.
§ 2.4.2 (p. 62) described the interactions between the const
qualifier and pointers. The same interactions exist between the volatile
qualifier and pointers. We can declare pointers that are volatile
, pointers to volatile
objects, and pointers that are volatile
that point to volatile
objects:
volatile int v; // v is a volatile int
int *volatile vip; // vip is a volatile pointer to int
volatile int *ivp; // ivp is a pointer to volatile int
// vivp is a volatile pointer to volatile int
volatile int *volatile vivp;
int *ip = &v; // error: must use a pointer to volatile
*ivp = &v; // ok: ivp is a pointer to volatile
vivp = &v; // ok: vivp is a volatile pointer to volatile
As with const
, we may assign the address of a volatile
object (or copy a pointer to a volatile
type) only to a pointer to volatile
. We may use a volatile
object to initialize a reference only if the reference is volatile
.
volatile
ObjectsOne important difference between the treatment of const
and volatile
is that the synthesized copy/move and assignment operators cannot be used to initialize or assign from a volatile
object. The synthesized members take parameters that are references to (nonvolatile
) const
, and we cannot bind a nonvolatile
reference to a volatile
object.
If a class wants to allow volatile
objects to be copied, moved, or assigned, it must define its own versions of the copy or move operation. As one example, we might write the parameters as const volatile
references, in which case we can copy or assign from any kind of Foo
:
class Foo {
public:
Foo(const volatile Foo&); // copy from a volatile object
// assign from a volatile object to a nonvolatile object
Foo& operator=(volatile const Foo&);
// assign from a volatile object to a volatile object
Foo& operator=(volatile const Foo&) volatile;
// remainder of class Foo
};
Although we can define copy and assignment for volatile
objects, a deeper question is whether it makes any sense to copy a volatile
object. The answer to that question depends intimately on the reason for using volatile
in any particular program.