From: Anthony Williams (anthony.williamsNOSPAM_at_[hidden])
Date: 2002-12-05 08:50:55
Gabriel Dos Reis writes:
> Anthony Williams <anthony.williamsNOSPAM_at_[hidden]> writes:
> | > Anthony Williams <anthony.williamsNOSPAM_at_[hidden]> writes:
> | >
> | > [...]
> | >
> | > | 3.10p15:
> | > | "If a program attempts to access the stored value of an object through an
> | > | lvalue of other than one of the following types the behavior is undefined:
> | > |
> | > | - the dynamic type of the object,
> | > |
> | > | ...
> | > |
> | > | - a char or unsigned char type."
> | > |
> | > | So given a Foo object foo, static_cast<char*>(static_cast<void*>(&foo)) is
> | > | legal, and can be used to access the object representation of the object.
> | >
> | > There is no question that the above cast is legal. I thin the issue
> | > is elsewhere. The key question is whether that may be different from
> | >
> | > reinterpret_cast<void*>(&foo);
> | I thought the issue was whether the pair of static_cast<>s in dangerous_cast<>
> | was as implementation defined as a reintepret_cast<> would be. If you read my
> | mail to the end, hopefully I have explained that I think that the
> | static_cast<> pair is legal and well-defined, as opposed to using
> | reinterpret_cast, which is implementation-defined. If I haven't made myself
> | clear, I apologise, and will try again.
> You made youself clear.
> However, there are two running issues originating from a claim of Dave
> that dangerous_cast<> might be better than reinterpret_cast<> in
> casting from U* to T* (dangerous_cast<> uses the intermediate step
> void* via static_cast<>).
> 1) is dangerous_cast<> better than reinterpret_cast<>?
> 2) is it well-defined to dereference the value obtained from
> U* -> void* -> T*
> You've showed that si U == char, (the case in Dave's example) then it
> is well-formed. The other cases are left undefined.
> So the key question (1) is still unanswered.
Well, given that we have a valid use when U==(unsigned) char, I think it is
certainly better than reinterpret_cast<> in that case.
However, for (2), it is only safe to dereference the resulting pointer if
there is a T at the location that the final T* points to. This is true
irrespective of what U is. However, there are very few cases in which you are
guaranteed to be able to get a valid U* that holds a valid T* --- given that U
and T may have different alignment requirements, and an implementation is
permitted to drop any unnecessary info from pointers, so T* and U* may only
store addresses which are valid multiples of the alignment for T and U
respectively, so it is unlikely that you would get a valid case, unless there
was special dispensation.
One of these is U==char or void, as I showed.
Another case to consider is when U is a POD-struct and T is the type of the
first data member (or vice-versa). In this case, reinterpret_cast<> is
guaranteed to work (9.2p17), so what about dangerous_cast<>? IMO, there is no
guarantee, though I would be surprised if it didn't work. Indeed, I read the
note on that paragraph to indicate that the intent is that the address is the
same, and thus static_cast<void*> will yield the same result. However, I can't
find any normative guarantee.
A third case to consider is when T and U are the types of members of the same
union. In this case, reinterpret_cast<> to a pointer to the union type and
back is guaranteed (since the members are to be allocated as if they were the
only member of a struct), and I would be surprised if it didn't work, but I
can't find a normative guarantee.
If these last two cases are guaranteed to be OK, then I think we have
sufficient to indicate that dangerous_cast<> can be useful. If not, then it
ought to be renamed, and only defined for char types.
-- Anthony Williams Senior Software Engineer, Beran Instruments Ltd. Remove NOSPAM when replying, for timely response.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk