Reputation: 159
I stumbled upon something very strange in the c++ syntax. A volatile* type.
This is the code that I found (in the Qt-library):
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{
if (receiver == 0) {
qWarning(""QCoreApplication::postEvent: Unexpected null receiver"");
delete event;
return;
}
QThreadData * volatile * pdata = &receiver->d_func()->threadData;
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ WHAT IS THIS???
QThreadData *data = *pdata;
if (!data) {
// posting during destruction? just delete the event to prevent a leak
delete event;
return;
}
// [...]
}
What I understood form this:
volatile * QThreadData * pdata
, because then I'd get a compiler error. That is obviously because objects cannot be volatile *
, but pointers can.pdata
is not a QThreadData *
, it has a QThreadData * volatile *
type. In an attempt to compile this code: int * volatile * x = new int(10);
I would get the following compiler error: "cannot convert 'int*' to 'int* volatile*' in initialization".So these are my questions:
QThreadData * volatile *
and what is the meaning of volatile *
?volatile *
a part of the type. Why isn't the type just QThreadData *
with a volatile *
property?Upvotes: 2
Views: 240
Reputation: 64308
The declaration QThreadData * volatile * pdata
means that pdata
is a pointer to a volatile pointer to a QThreadData
.
In general, volatile
means that the object in can change in ways beyond the compiler's control. For example, if it is stored in memory that is written to by other hardware. This means that the compiler must read the value from memory every time that it is needed instead of making the assumption that if it has read the value before and it hasn't made a change to that memory location, that the value is still the same.
So in this case, pdata
itself is not volatile. This means the compiler is allowed to assume that pdata
won't change unexpectedly. However, what pdata
points to can change unexpectedly, and what it is pointing to is another pointer. Furthermore, what that other volatile pointer is pointing to (the actual QThreadData) is not itself volatile.
In C++, const
and volatile
are treated very similarly. They both indicate that the object has some special property. By requiring these properties to be carried along with the type, certain mistakes can be more easily avoided. This is easier to see for const
, but the same logic applies for volatile
. For example
void f(int *p)
{
*p += 2;
*p += 3;
}
int main()
{
volatile int a = 5;
f(&a); // error: can't convert volatile int * to int *
}
Since the function f
is compiled separately from the function main
, the compiler wouldn't know, when it is compiling the function f
, that it should not assume that *p
won't change unexpectedly. Without this knowledge, it might change the code to effectively be
*p += 5;
but this would be wrong, since *p might change between the two additions.
Upvotes: 6
Reputation: 385098
To help fix your confusion, the first thing you should know is that you have a double-pointer type.
The next thing to say is that volatile
-ness is part of a type just like const
-ness is part of a type: together this fact is called cv-qualification.
[C++11: 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. See 1.9 for detailed semantics. In general, the semantics ofvolatile
are intended to be the same in C++ as they are in C. _ — end note ]_
The phrase volatile *
isn't any one specific thing: it is two tokens within the type that could mean a number of things.
In this case, you have a QThreadData* volatile*
, which is the "pointer to volatile pointer to QThreadData
" type. Read it from right-to-left.
If you stripped the volatile
out, you'd be left with a QThreadData**
.
If you wanted a more simple example, here's two:
int volatile x = 5;
volatile int y = 6;
See, just like const
, here we can play with the order of the cv-qualifier a little because there's no ambiguity.
Let's step up the example a little:
int volatile* p = new int volatile(5);
Now we have a pointer to an int volatile
(again, the same as a volatile int
). The volatile
applies left-wards; that is, to the int
, not the *
.
But we could also have a volatile pointer! Let's say, a volatile pointer to a non-volatile int:
int* volatile p = new int(5);
And I have no idea what you mean by "property".
Upvotes: 6