when should a member function be both const and volatile together? - c++

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;
}

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.

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.

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.

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.

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.

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.

Related

May the compiler optimize out stores though a pointer-to-volatile? [duplicate]

This question already has answers here:
Does accessing a declared non-volatile object through a volatile reference/pointer confer volatile rules upon said accesses?
(4 answers)
Closed 2 years ago.
Writes to volatile variables are somehow side effects in C++ and generally can't be optimized out under as-if rule, usually. In practice, this usually means that on inspection of the assembly you'll see one one store for each volatile store by the abstract machine1.
However, it isn't clear to me if the stores must be performed in the following case where the underlying object is not volatile, but the stores are done through a pointer-to-volatile:
void vtest() {
int buf[1];
volatile int * vptr = buf;
*vptr = 0;
*vptr = 1;
*vptr = 2;
}
Here, gcc does in fact optimize out all of the stores. Clang does not. Oddly, the behavior depends on the buffer size: with buf[3] gcc emits the stores, but with buf[4] it doesn't and so on.
Is gcc's behavior here legal?
[1] with some small variations, e.g., some compilers will use a single read-modify-write instruction on x86 to implement something like v++ where v is volatile).
While it would be useful for the C and C++ Standards to recognize a categories of implementations where volatile loads and stores have particular semantics, and report via predefined macros, intrinsics, or other such means what semantics a particular implementation is using, neither implementation presently does so. Given a loop:
void hang_if_nonzero(int mode)
{
int i = 1;
do { +*(volatile int*)0x1234; } while(mode);
}
a compiler would be required to generate code that will block program execution if mode is non-zero, because the volatile read is defined as being a side effect in and of itself, regardless of whether there is any means by which the effect of executing it could be distinguished from that of skipping it. There would be no requirement, however, that the compiler actually generate any load instructions for the volatile access. If the compiler specified that it was only for use on hardware platforms where the effect of reading address 0x1234 would be indistinguishable from the effect of skipping the read, it would be allowed to skip the read.
In cases where an object's address is taken, but a compiler can account for all the ways in which the address is used and code never inspects the representation of the address, a compiler would not be required to allocate "normal" addressable storage but may at its leisure allocate a register or other form of storage which wouldn't be accessed via normal loads and stores. It may even pretend to allocate storage without actually doing so if it can tell what value an object would contain when accessed. If e.g. a program were to do something like:
int test(int mode)
{
int a[2] = {1,2};
int *p = a;
return p[mode & 1] + p[mode & 1];
}
a compiler wouldn't be required to actually allocate any storage for a, but could instead at its leisure generate code equivalent to return (1+(mode & 1)) << 1;. Even if p were declared as int volatile *p = a;, that would not create a need for the compiler to allocate addressable storage for a, since a compiler could still account for everything done through pointers to a and would thus have no obligation to keep a in addressable storage. A compiler would thus be allowed to treat a read of a[mode & 1] as equivalent to evaluating the expression (1+(mode & 1)). If the read were done through a volatile pointer, then it would need to be treated as a side effect for purposes of determining whether a loop may be omitted, but there would be no requirement that the read itself actually do anything.

Reading a struct from a read only memory

I'm working on a embedded system, where some calibration data is stored in the flash memory. The calibration data is stored in a struct which is placed in a special section that the linker knows to place in the flash:
struct data_block {
calibration_data mData;
uint16_t mCheckSum;
};
//Define to compile the fixed flash location for image data
const data_block __attribute__((section (".caldata"))) gCalibrationData{};
where calibration_data is another POD struct which contains the actual values.
The problem is that if I now simply write the following:
const data_block data{gCalibrationData};
if (CheckSum(&(data.mData)) == data.mCheckSum) {
//do stuff
} else {
//Error
}
this always goes to the error branch, even though the actual checksum in flash is absolutely correct (writing this a bit differently makes it work, see below).
This is of course understandable: the compiler sees a const global object, which is default-initialized, so it knows all the values, so I guess it actually optimizes out the whole if (if I debug-printf data via a uint16_t *, I actually get the correct values).
The way I think would be correct is to define
const volatile data_block __attribute__((section (".caldata"))) gCalibrationData{};
However, now I have the problem that I can't assign a volatile struct to non-volatile, i.e. const data{gCalibrationData}; does not compile. The same problem also appears if I try to access through a const volatile data_block *.
There's at least two or three ways I can make this work, and I don't like any of them:
remove the const (and volatile) qualifier from gCalibrationData. However, this is a bit of a hack based on the compiler not being clever enough to guarantee that gCalibrationData is never touched in my program, and on the other hand, I'd like to keep to const qualifier, since trying to write to gCalibrationData by assigning is a hard fault.
access gCalibrationData via const gCalibrationData * volatile pData (yes, the volatile is exactly where I mean it). Accessing through a pointer which is volatile forces the compiler to actually load the data. Again, this seems like a hack, since the pointer itself certainly isn't volatile.
give data_block and calibration_data an assignment operator taking const volatile &, and assign field by field in them. This seems to be correct from the language point of view, but then whenever calibration_data changes I need to edit the assignment operator by hand. Failing to do so will produce hard-to-detect bugs.
My question: what would be the correct way to read the calibration data? My ideal criteria would be:
the global object itself is const, to catch unintended writes.
no undefined behaviour
access by assigning the struct directly to another struct
or at least so that I'm not required to remember to assign each variable of primitive type in calibration_data, see option 3. above
bonus points for thread-safety, although in my specific case only a single thread ever reads or writes the flash (all other "threads" are interrupts).
One solution could be to declare a buffer in a separate source file, to inform the linker of size of data_block and then define gCalibrationData to be a symbol whose value is the begining of this buffer:
data_block.cpp:
//no initialization performed here, just used to
//transmit to the linker the information of the size
//and alignment of data_block
extern "C"{//simpler name mangling
[[gnu::section(".caldata")]] volatile
aligned_storage<sizeof(data_block),alignof(data_block)> datablock_buffer;
}
//then we specify that gCalibrationData refers to this buffer
extern const volatile data_block
gCalibrationData [[gnu::alias("datablock_buffer")]];
Alternatively the definition of gCalibrationData symbol can be done via a linker script:
SECTIONS{
.caldata : {
gCalibrationData = . ;
data_block.o(.caldata)
}
}
gCalibrationData is an alias to an data_block_buffer. This will not cause undefined behavior because such aliasing is permitted by the language: data_block_buffer provides storage for gCalibrationData.
Semanticaly, the extern specifier is used to say that this declaration is not a definition of the value of gCalibrationData. Nevertheless the alias attribute is a definition of the symbol for the linker.
data_block.hpp
extern const volatile data_block gCalibrationData;
//and copy must be enabled for volatile:
struct data_block{
/*...*/
data_block(const data_block&) =default;
data_block& operator=(const data_block&) =default;
data_block(const volatile data_block& other){
//the const cast means: you are responsible not to
//perform this operation while performing a rom update.
memcpy(this,const_cast<const data_block*>(&other);
}
data_block& operator=(const volatile data_block& other){
memmove(this,const_cast<const data_block*>(&other);
//or memcpy if you are sure a self assignment will never happen.
return *this;
}
};
The most practical approach would be to lose the const. By a strict reading of the standard, gCalibrationData shouldn't be allowed to be const, since writing to a const object -- regardless of who does it -- leads to undefined behavior.
Failing that, though, just define it as extern const (and, if necessary to placate the linker, put the non-extern definition in its own translation unit. That will get you your const-correctness checking, allow the compiler to, e.g., do hoisting optimizations based on the initial values of the calibration data, while still preventing it from making any specific assumptions about those values at compile time.

Why do all the member functions in std::atomic appear both with and without volatile?

I noticed that most member functions of std::atomic<T> types are declared twice, once with the volatile modifier and once without (example)). I checked the source code of the G++ standard library implementation and I found all of them to be exact duplicates, for example,
bool
load(memory_order __m = memory_order_seq_cst) const noexcept
{ return _M_base.load(__m); }
bool
load(memory_order __m = memory_order_seq_cst) const volatile noexcept
{ return _M_base.load(__m); }
I could not find any example where the volatile variant behaves differently than the non-volatile one, differs in return type or anything of that sort.
Why is that? I thought a volatile member function could also be called in objects which are not volatile. So declaring and defining std::atomic::load(...) const volatile noexcept etc. should be enough.
Update:
Based on the comments my question basically boils down to: Can you provide an example where some calls using a non-volatile instance (not necessarily of std::atomic) would generate a different assembly in the two following cases,
every member function appears with the same body with and without volatile,
only the volatile variant exists?
This, assuming the compiler can do whatever optimization the standard allows it to (or simply highest optimization levels).
Probably it all stems from what volatile is, for that see this answer. As the use-cases are quite slim compare to usual application development, that is why nobody usually cares. I will assume that you do not have any practical scenario where you wondering if you should apply those volatile overloadings. Then I will try to come up with an example where you may need those (do not judge it to be too real).
volatile std::sig_atomic_t status = ~SIGINT;
std::atomic<int> shareable(100);
void signal_handler(int signal)
{
status = signal;
}
// thread 1
auto old = std::signal(SIGINT, signal_handler);
std::raise(SIGINT);
int s = status;
shareable.store(10, std::memory_order_relaxed);
std::signal(SIGINT, old);
// thread 2
int i = shareable.load(std::memory_order_relaxed);
memory_order_relaxed guarantees atomicity and modification order consistency, no side-effects. volatile cannot be reordered with side-effects. Then here we are, in thread 2 you can get shareable equal 10, but status is still not SIGINT. However, if you set type qualifier to volatile of shareable that must be guaranteed. For that you will need the member methods be volatile-qualified.
Why would you do something like this at all? One case, I might think of, is you have some old code that is using old volatile-based stuff and you cannot modify it for one or another reason. Hard to imagine, but I guess that there might be a need to have some kind of guaranteed order between atomic and volatile inline assembly. The bottom line, IMHO, is that whenever it is possible you can use new atomic library instead of volatile objects, in the case there are some volatile objects, that you cannot rid of, and you want to use atomic objects, then you might need volatile qualifier for the atomic objects to have proper ordering guarantees, for that you would need overloading.
UPDATE
But if all I wanted was to have atomic types usable as both volatile and non-volatile, why not just implement the former?
struct Foo {
int k;
};
template <typename T>
struct Atomic {
void store(T desired) volatile { t = desired; }
T t;
};
int main(int i, char** argv) {
//error: no viable overloaded '='
// void store(T desired) volatile { t = desired; }
Atomic<Foo>().store(Foo());
return 0;
}
The same would be with load and other operations, because those are usually not trivial implementations that require copy operator and/or copy constructor (that also can volatile or non-volatile).

Can a pointer be volatile?

Consider the following code:
int square(volatile int *p)
{
return *p * *p;
}
Now, the volatile keyword indicates that the value in a
memory location can be altered in ways unknown to the compiler or have
other unknown side effects (e.g. modification via a signal interrupt,
hardware register, or memory mapped I/O) even though nothing in the
program code modifies the contents.
So what exactly happens when we declare a pointer as volatile?
Will the above mentioned code always work, or is it any different from this:
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
Can we end up multiplying different numbers, as pointers are volatile?
Or is there better way to do so?
Can a pointer be volatile?
Absolutely; any type, excluding function and references, may be volatile-qualified.
Note that a volatile pointer is declared T *volatile, not volatile T*, which instead declares a pointer-to-volatile.
A volatile pointer means that the pointer value, that is its address and not the value pointed to by, may have side-effects that are not visible to the compiler when it's accessed; therefore, optimizations deriving from the "as-if rule" may not be taken into account for those accesses.
int square(volatile int *p) { return *p * *p; }
The compiler cannot assume that reading *p fetches the same value, so caching its value in a variable is not allowed. As you say, the result may vary and not be the square of *p.
Concrete example: let's say you have two arrays of ints
int a1 [] = { 1, 2, 3, 4, 5 };
int a2 [] = { 5453, -231, -454123, 7565, -11111 };
and a pointer to one of them
int * /*volatile*/ p = a1;
with some operation on the pointed elements
for (int i = 0; i < sizeof(a1)/sizeof(a1[0]); ++i)
*(p + i) *= 2;
here p has to be read each iteration if you make it volatile because, perhaps, it may actually point to a2 due to external events.
Yes, you can of course have a volatile pointer.
Volatile means none more and none less than that every access on the volatile object (of whatever type) is treated as a visible side-effect, and is therefore exempted from optimization (in particular, this means that accesses may not be reordered or collapsed or optimized out alltogether). That's true for reading or writing a value, for calling member functions, and of course for dereferencing, too.
Note that when the previous paragraph says "reordering", a single thread of execution is assumed. Volatile is no substitute for atomic operations or mutexes/locks.
In more simple words, volatile generally translates to roughly "Don't optimize, just do exactly as I say".
In the context of a pointer, refer to the exemplary usage pattern given by Chris Lattner's well-known "What every programmer needs to know about Undefined Behavior" article (yes, that article is about C, not C++, but the same applies):
If you're using an LLVM-based compiler, you can dereference a "volatile" null pointer to get a crash if that's what you're looking for, since volatile loads and stores are generally not touched by the optimizer.
Yes. int * volatile.
In C++, keywords according to type/pointer/reference go after the token, like int * const is constant pointer to integer, int const * is pointer to constant integer, int const * const is constant pointer to constant integer e.t.c. You can write keyword before the type only if it's for the first token: const int x is equal to int const x.
The volatile keyword is a hint for the compiler (7.1.6.1/7):
Note:
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. Furthermore,
for some implementations,
volatile
might indicate that special hardware instructions are required to access
the object. See
1.9
for detailed semantics. In general, the semantics of
volatile
are intended to be the
same in C
++
as they are in C.
— end note
]
What does it mean? Well, take a look at this code:
bool condition = false;
while(!condition)
{
...
}
by default, the compiler will easilly optimize the condition out (it doesn't change, so there is no need to check it at every iteration). If you, however, declare the condition as volatile, the optimization will not be made.
So of course you can have a volatile pointer, and it is possible to write code that will crash because of it, but the fact that a variable is volative doesn't mean that it is necessarily going to be changed due to some external interference.
Yes, a pointer can be volatile if the variable that it points to can change unexpectedly even though how this might happen is not evident from the code.
An example is an object that can be modified by something that is external to the controlling thread and that the compiler should not optimize.
The most likely place to use the volatile specifier is in low-level code that deals directly with the hardware and where unexpected changes might occur.
You may be end up multiplying different numbers because it's volatile and could be changed unexpectedly. So, you can try something like this:
int square(volatile int *p)
{
int a = *p;
return a*a;
}
int square(volatile int *p)
{
int a = *p;
int b = *p
return a*b;
}
Since it is possible for the value of *ptr to change unexpectedly, it is possible for a and b to be different. Consequently, this code could return a number that is not a square! The correct way to code this is:
long square(volatile int *p)
{
int a;
a = *p;
return a * a;
}

C++ reinterpret_cast - will this always work correctly?

I have written MyString and MyStringConst class. Now I need from time to time pass MyString as MyStringConst, hence overload cast operator. I have written this
MyString::operator const MyStringConst &() const
{
return reinterpret_cast<const MyStringConst &>(*this);
}
MyString has this data
char * str;
int length;
volatile int hashCode;
int bufferSize;
MyStringConst has this data
const char * c_str;
int length;
volatile int hashCode;
Plus there are some methods, that in both strings can recalculate hashCode.
Is this code correctly written. I have tested it on MSVC 2013 and it is working correctly, but I have no idea if it can be used in production code, that can be compiled with different compiler.
The common initial sequence of the data member is different and C++ makes no guarantee at all about the layout in this case, even if the types differ only by const qualification. Otherwise the guarantees for unions would effectively imply that the types need to have a common layout if they are standard-layout types (according to a note in 9.5 [class.union] paragraph 1).
In practice I would expect that the two types are laid out identical and that the reinterpret_cast works but there is no guarantee by the standard. Based on your comment MyStringConst merely holds a pointer to the string, i.e., instead of converting to references, I would just return a suitably constructed MyStringConst and avoid relying on undefined behavior:
MyString::operator MyStringConst() const {
return MyStringConst(str, length);
}
The MyString object still has to live as long as the result from the conversion but this is no different to the case using reinterpret_cast.
BTW, the volatile on the hashCode is ill-advised: the only effect it will have is to slow down the program. I guess you are trying to use it to achieve synchronization between threads but in C++ volatile doesn't help with that at all: you get a data race when writing the member in one thread it is also accessed unsynchronized in another thread. You'd spell the member
std::atomic<int> hashCode;
instead.