#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?
}
reinterpret_cast
是否保证永远不会更改其操作数的值?
答案 0 :(得分:3)
reinterpret_cast是否保证它永远不会改变其操作数的值?
TL; DR 我认为是,在某些情况下。
只要目标类型的对齐要求不比源类型更严格,保证就应该保持。否则转换的影响未指定。
最简单的方法是询问标准,特别是:§5.2.10[expr.reinterpret.cast]
7 /对象指针可以显式转换为不同类型的对象指针.70当“指向T1的指针”类型的prvalue v转换为“指向 cv T2的指针”时“,如果T1和T2都是标准布局类型(3.9),并且T2的对齐要求不比T1更严格,或者两种类型都是
static_cast<cv T2*>(static_cast<cv void*>(v))
,则结果为void
。将“指向T1的指针”类型的prvalue转换为“指向T2的指针”类型(其中T1和T2是对象类型,T2的对齐要求不比T1更严格)并返回其原始类型会产生原始类型指针值。任何其他此类指针转换的结果都未指定。
在您的情况下,因为此层次结构中没有virtual
方法,所以类型为标准布局类型。并且因为两者都具有相同的对齐要求(因为它们包含相同的值),所以我们确实匹配了明确指定的效果,因此:
reinterpret_cast<I2*>(d)
相当于:
static_cast<I2*>(static_cast<void*>(d))
因此我们需要回到§5.2.9[expr.static.cast] :
7 /任何标准转换序列(第4章)的反转,不包含左值到右值(4.1),数组到指针(4.2),函数到指针(4.3),空指针(4.10) ),null成员指针(4.11)或布尔(4.12)转换可以使用
static_cast
显式执行。如果程序使用static_cast
执行格式错误的标准转换序列的反转,则该程序格式不正确。
T*
至void*
是根据§4.10[conv.ptr] 第2段的标准转换序列;所以我假设这意味着从static_cast
到void*
的{{1}}应该产生相同的地址(假设它符合T*
的对齐要求第一名)。
13 /类型“指向 cv1 void的指针”的prvalue可以转换为“指向 cv2 T的指针”的prvalue,其中T是对象类型和 cv2 是相同的cv资格,或者比 cv1 更高的cv资格。空指针值将转换为目标类型的空指针值。指向对象的类型指针的值转换为“指向 cv
T
的指针”并返回,可能具有不同的cv资格,应具有其原始值。 [示例:void
- 示例]
不幸的是,这个例子是关闭的(与你的情况相比);所以我们从中得不到多少。我刚才引用它是因为它是完全相关的。
答案 1 :(得分:1)
没有。 好吧,我必须在这里键入一些无数字符来满足SO傻瓜,但答案仍然是一样的。但是,我可能会使用这些额外的文本来提及当然,您所拥有的有效保证可能比神圣的C ++标准提供的更实用。但是,对于有大脑的人来说这是显而易见的(程序员通常都不会这样),所以听起来可能听起来有点光顾,但第三方面,这应该足够SO了。
哦,现在看看你的代码,我认为第一个断言不应该保持(一般),因为我记得基本子对象的内存顺序没有任何保证。你可能想检查一下。同样在实践中通过对其他基类做同样的事情。