This is basically a continuation of this question. So far it looks like that if I have a function like this:
void SecureZeroMemory( void* ptr, size_t cnt )
{
volatile char *vptr = (volatile char *)ptr;
while (cnt) {
*vptr = 0;
vptr++;
cnt--;
}
}
and call it like this:
{
char buffer[size];
SecureZeroMemory( buffer, size );
}
then since buffer
is not declared volatile it doesn't matter that a pointer to volatile is used - the data itself is not volatile, so write to the variable do not constitute observable behavior (1.9/6) and the compiler is allowed to optimize them away.
However recently I've come across a statement that it's only the pointer declaration that matters. Specifically C++03 5.3.1/1 describes indirection (*) like this:
The unary * operator performs indirection [...] If the type of the expression is “pointer to T,” the type of the result is “T.”
So the claim is that because of using indirection on a volatile char*
we get volatile char
and writes to those do constitute observable behavior and it no longer matters how the actual data is declared.
Does the C++03 5.3.1/1 description of indirection really guarantee that overwriting memory using a volatile T*
pointer as in the sample above constitute observable behavior and is disallowed to be optimized away?
I'm pretty sure all that "new" quote adds is that *vptr
is an lvalue expression with type volatile char
.
The type of the lvalue doesn't affect the type of the object to which that lvalue expression refers, for the same reason that a pointer-to-const that points at a non-const object doesn't somehow make the object const. So the original analysis isn't affected this quote -- the object still doesn't have volatile-qualified type.
In normal parlance we'd say that the type of *vptr
is volatile char &
, but 5/5 says, "If an expression initially has the type “reference to T” the type is adjusted to T prior to any further analysis". That's the reason why *vptr
is said to have type volatile char
, not volatile char &
-- before analysing any expression you remove the reference from the type, even if it's an lvalue.
[Edit: my answer used to have some text about cv-qualifications being insignificant for non-object values of integer type. It was true (lvalue-to-rvalue conversions of non-class types discard cv-qualifiers, 4.1/1) but irrelevant (I mistakenly thought that because the text you quoted mentioned a non-reference type it was talking about the type after this conversion)]