Reputation: 35460
I was reading about volatile member function and came across an affirmation that member function can be both const and volatile together. I didn't get the real use of such a thing. Can anyone please share their experience on practical usage of having member function as const and volatile together.
I wrote small class to test the same:
class Temp
{
public:
Temp(int x) : X(x)
{
}
int getX() const volatile
{
return X;
}
int getBiggerX()
{
return X + 10;
}
private:
int X;
};
void test( const volatile Temp& aTemp)
{
int x = aTemp.getX();
}
int main(int argc, char* argv[])
{
const volatile Temp aTemp(10);
test(aTemp);
return 0;
}
Upvotes: 11
Views: 5701
Reputation: 297
An object marked as const volatile will not be allowed to change by the code where it is declared. The error will be raised due to the const qualifier. The volatile part of the qualifier means that the compiler cannot optimize the code with respect to the object.
In an embedded system this is typically used to access hardware registers that can be read and are updated by the hardware, so it makes no sense to be able to write to the register via the code. An example might be the status register of a serial port.Various bits will indicate a status like if a character is waiting to be read. Each read to this status register could result in a different value depending on what else has occurred in the serial port hardware. It makes no sense to write to the status register but you need to make sure that each read of the register results in an actual read of the hardware.
Below is an illustration :
//We assume that the below declared pointers
//point to the correct
//hardware addresses
unsigned int const volatile *status_reg;
unsigned char const volatile *recv_reg;
#define CHAR_READ 0x01
int get_next_char()
{
while((*status_reg & CHAR_READ) == 0);
return *recv_reg;
}
Hope this helps.
Regards Sandipan Karmakar.
Upvotes: 1
Reputation: 905
One situation I can think of that could require both const and volatile on a member function would be in an embedded systems situation where you had a the function was logically const but actually had to modify a data cache in a shared memory location (e.g. building a bitmap on demand and caching the bitmap in case the same bitmap was needed again soon). It certainly does not come up very often.
Upvotes: 1
Reputation:
I think that the reason we have "const volatile" functions is the same as the reason we have "protected" inheritance: The grammar allows it , so we had better think up a meaning for it.
Upvotes: 1
Reputation: 111150
The cv qualification distilled means:
I won't change the value, but there is something out there that can.
You are making a promise to yourself that you won't change the value (const
qualification) and requesting the compiler to keep its slimy hands off of this object and turn off all optimization (volatile
qualification). Unfortunately, there is little standard among the compiler vendors when it comes to treating volatile
fairly. And volatile
is a hint to the compiler after all.
A practical use case of this is a system clock. Supposing 0xDEADBEEF was your system specific address of a hardware clock register you'd write:
int const volatile *c = reinterpret_cast<int *>(0xDEADBEEF);
You can't modify that register value, but each time you read it, it is likely to have a different value.
Also, can use this to model UARTs.
Upvotes: 17
Reputation: 507005
You asked for a practical example of volatile member functions. Well i can't think of one because the only situations i could imagine are so low-level that i would not consider using a member function in the first place, but just a plain struct with data-members accessed by a volatile reference.
However, let's put a const volatile function into it just for the sake of answering the question. Assume you have a port with address 0x378h that contains 2 integers, 4 bytes each. Then you could write
struct ints {
int first;
int second;
int getfirst() const volatile {
return first;
}
int getsecond() const volatile {
return second;
}
// note that you could also overload on volatile-ness, just like
// with const-ness
};
// could also be mapped by the linker.
ints const volatile &p = *reinterpret_cast<ints*>(0x378L);
You are stating
I'm not changing them, but another thing outside this abstract semantics could change it. So always do a real load from its address.
Actually, volatile signals that the value of an object might not be the value last stored into it but is actually unknown and might have been changed in between by external (not observable by the compiler) conditions. So when you read from a volatile object, the compiler has to emulate the exact abstract semantics, and perform no optimizations:
a = 4;
a *= 2;
// can't be optimized to a = 8; if a is volatile because the abstract
// semantics described by the language contain two assignments and one load.
The following already determines what volatile
does. Everything can be found in 1.9
of the Standard. The parameters it talks about are implementation defined things, like the sizeof of some type.
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below. [...]
A conforming implementation executing a well-formed program shall produce the same observable behavior as one of the possible execution sequences of the corresponding instance of the abstract machine with the same program and the same input. [...]
The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions.
Upvotes: 14
Reputation: 247999
I've never needed anything being both const and volatile, but here's my guess:
Const: You, your code, is not allowed to change the value.
Volatile: The value may change over time without your program doing anything.
So some read-only data exposed by another process or by some hardware would be const and volatile. It could even be memory-mapped into your process and the page marked read-only, so you'd get an access violation if you tried to write to it if it wasn't const.
Upvotes: 1