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

-- 
Anthony Williams
Senior Software Engineer, Beran Instruments Ltd.
Remove NOSPAM when replying, for timely response.