From: Bill Wade (bill.wade_at_[hidden])
Date: 2000-08-24 11:52:10


> From: David Abrahams [mailto:abrahams_at_[hidden]]

> > struct Rule
> > {
> > unsigned long cost;
> > const void* action;
> > const char** symbols(){ return (const char**) (&action+1); }
> > };
>
> Okay, but is this still a POD?

Yes. The addition of a non-virtual member function (other than 'tors and
maybe assignment, I don't remember) is not enough to turn a POD struct into
a non-POD struct.

> And if action were of type char instead of
> const void*, then your symbols() array would most likely be misaligned.

Correct. In that case you'd need to do something extra to ensure alignment.

> It seems to me that ((const char**)symbols)[2] has to work, in
> any case. The
> reasoning? The compiler is not allowed to perform bounds checking on a raw
> pointer, and the expression above creates a temporary raw pointer before
> indexing it. Am I missing something?

The compiler is allowed to perform bounds checking on a raw pointer. I
don't think you can find anything in the standard that guarantees

   void* x = new char[10];
   (char*)x+20;

has defined behavior. On the other hand, for the struct hack the math on
the raw_pointer stays within a contiguous block of memory that you have
allocated. I think that means that you should be ok. However the standard,
in general, takes a dim view of casting a pointer between unrelated types.
Almost all implementations are much more forgiving than the standard.
    int i;
    assert(&i == (void*)(short*)(void*)&i);
I've never used an implementation that would trip the assert, but the
standard allows this to fail, and it probably invokes undefined behavior.