#include <cassert>

struct A { int a; };
struct I1 : A { int a; };
struct I2 : A { int a; };
struct D : I1, I2 { int a; };

using namespace std;

int main()
{
    auto d  = new D;

    auto a = static_cast<I2*>(d);
    assert((void*)(a) != (void*)(d)); // OK

    auto b = reinterpret_cast<I2*>(d);
    assert((void*)(b) == (void*)(d)); // OK under VC++. Is it guaranteed?
}

Does reinterpret_cast guarantee it will never change the value of its operand?

有帮助吗?

解决方案

Does reinterpret_cast guarantee it will never change the value of its operand?

TL;DR I think Yes, under some conditions.

The guarantee should hold as long as the destination type has an alignment requirement no stricter than the source type. Otherwise the effect of the conversion is unspecified.


The simplest way is to ask the Standard, and specifically: §5.2.10 [expr.reinterpret.cast]

7/ An object pointer can be explicitly converted to an object pointer of a different type.70 When a prvalue v of type “pointer to T1” is converted to the type “pointer to cv T2”, the result is static_cast<cv T2*>(static_cast<cv void*>(v)) if both T1 and T2 are standard-layout types (3.9) and the alignment requirements of T2 are no stricter than those of T1, or if either type is void. Converting a prvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type yields the original pointer value. The result of any other such pointer conversion is unspecified.

In your case since there is no virtual method in this hierarchy, the types are standard-layout types. And since indeed both have the same alignment requirements (as they contain the same values), then indeed we match the well-specified effects here and thus:

reinterpret_cast<I2*>(d)

is equivalent to:

static_cast<I2*>(static_cast<void*>(d))

Thus we need go back to §5.2.9 [expr.static.cast]:

7/ The inverse of any standard conversion sequence (Clause 4) not containing an lvalue-to-rvalue (4.1), array-to-pointer (4.2), function-to-pointer (4.3), null pointer (4.10), null member pointer (4.11), or boolean (4.12) conversion, can be performed explicitly using static_cast. A program is ill-formed if it uses static_cast to perform the inverse of an ill-formed standard conversion sequence.

T* to void* is a standard conversion sequence according to §4.10 [conv.ptr], paragraph 2; so I suppose this means that a static_cast from void* to T* should yield the same address (supposing it matches the alignment requirements of T in the first place).

13/ A prvalue of type “pointer to cv1 void” can be converted to a prvalue of type “pointer to cv2 T,” where T is an object type and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1. The null pointer value is converted to the null pointer value of the destination type. A value of type pointer to object converted to “pointer to cv void” and back, possibly with different cv-qualification, shall have its original value. [ Example:

T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true.

—end example ]

Unfortunately, the example is off (compared to your case); so we don't get much from this. I just cited it for completeness since it was related.

其他提示

No. Well I have to type some umpteen characters here to satisfy SO sillyrules, but the answer's still the same. However, I might use this extra text to mention that of course the effective guaranteees you have can be more practical than what the holy C++ standard offers. But then, that's evident to anyone with a brain (as programmers are wont to have), so it might sound a bit patronizing to mention that, but on the third hand, this should be enough text for SO.


Oh, now looking at your code, I think the first assertion should not hold (in general), because as I recall nothing is guaranteed about the memory order of base class sub-objects. You might want to check that. Also in practice by doing the same with other base class.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top