reinterpret_cast是否保证它永远不会改变其操作数的值?

时间:2014-03-13 06:48:31

标签: c++ c++11 compiler-construction type-conversion portability

#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是否保证永远不会更改其操作数的值?

2 个答案:

答案 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_castvoid*的{​​{1}}应该产生相同的地址(假设它符合T*的对齐要求第一名)。

  

13 /类型“指向 cv1 void的指针”的prvalue可以转换为“指向 cv2 T的指针”的prvalue,其中T是对象类型和 cv2 是相同的cv资格,或者比 cv1 更高的cv资格。空指针值将转换为目标类型的空指针值。指向对象的类型指针的值转换为“指向 cv T的指针”并返回,可能具有不同的cv资格,应具有其原始值。 [示例:

void
     

- 示例]

不幸的是,这个例子是关闭的(与你的情况相比);所以我们从中得不到多少。我刚才引用它是因为它是完全相关的。

答案 1 :(得分:1)

没有。 好吧,我必须在这里键入一些无数字符来满足SO傻瓜,但答案仍然是一样的。但是,我可能会使用这些额外的文本来提及当然,您所拥有的有效保证可能比神圣的C ++标准提供的更实用。但是,对于有大脑的人来说这是显而易见的(程序员通常都不会这样),所以听起来可能听起来有点光顾,但第三方面,这应该足够SO了。


哦,现在看看你的代码,我认为第一个断言不应该保持(一般),因为我记得基本子对象的内存顺序没有任何保证。你可能想检查一下。同样在实践中通过对其他基类做同样的事情。