reinterpret_cast是否保证永远不会更改其操作数的值? #包括 结构A{int A;}; 结构I1:A{int A;}; 结构I2:A{int A;}; 结构D:I1,I2{inta;}; 使用名称空间std; int main() { 自动d=新d; 自动a=静态(d); 断言((void*)(a)!=(void*)(d));//确定 自动b=重新解释铸件(d); assert((void*)(b)==(void*)(d));//在VC++下可以。有保证吗? }

reinterpret_cast是否保证永远不会更改其操作数的值? #包括 结构A{int A;}; 结构I1:A{int A;}; 结构I2:A{int A;}; 结构D:I1,I2{inta;}; 使用名称空间std; int main() { 自动d=新d; 自动a=静态(d); 断言((void*)(a)!=(void*)(d));//确定 自动b=重新解释铸件(d); assert((void*)(b)==(void*)(d));//在VC++下可以。有保证吗? },c++,c++11,compiler-construction,type-conversion,portability,C++,C++11,Compiler Construction,Type Conversion,Portability,重新解释强制转换是否保证它永远不会更改其操作数的值。 我必须在这里输入无数个字符来满足这些愚蠢的规则,但答案还是一样的。不过,我可能会用这篇额外的文字来提及,当然,你所能得到的有效保障比圣典C++标准所提供的更实用。但是,这对任何一个有头脑的人来说都是显而易见的(程序员是不会有的),所以提到这一点可能听起来有点傲慢,但从第三方面来说,这应该足够了 哦,现在看看你的代码,我认为第一个断言不应该成立(一般来说),因为我记得基类子对象的内存顺序没有任何保证。你可能想检查一下。在实践中,也可以对其他基

重新解释强制转换是否保证它永远不会更改其操作数的值。 我必须在这里输入无数个字符来满足这些愚蠢的规则,但答案还是一样的。不过,我可能会用这篇额外的文字来提及,当然,你所能得到的有效保障比圣典C++标准所提供的更实用。但是,这对任何一个有头脑的人来说都是显而易见的(程序员是不会有的),所以提到这一点可能听起来有点傲慢,但从第三方面来说,这应该足够了


哦,现在看看你的代码,我认为第一个断言不应该成立(一般来说),因为我记得基类子对象的内存顺序没有任何保证。你可能想检查一下。在实践中,也可以对其他基类执行相同的操作。

否。 我必须在这里输入无数个字符来满足这些愚蠢的规则,但答案还是一样的。不过,我可能会用这篇额外的文字来提及,当然,你所能得到的有效保障比圣典C++标准所提供的更实用。但是,这对任何一个有头脑的人来说都是显而易见的(程序员是不会有的),所以提到这一点可能听起来有点傲慢,但从第三方面来说,这应该足够了


哦,现在看看你的代码,我认为第一个断言不应该成立(一般来说),因为我记得基类子对象的内存顺序没有任何保证。你可能想检查一下。在实践中,也可以对其他基类执行相同的操作

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

TL;DR我认为是的,在某些情况下

只要目标类型的对齐要求不比源类型更严格,该保证就应有效。否则,未指定转换的效果


最简单的方法是询问标准,特别是:§5.2.10[expr.reinterpret.cast]

7/对象指针可以显式转换为不同类型的对象指针。70当类型为“指向T1的指针”的PRV值转换为类型为“指向cv T2的指针”时,如果T1和T2都是标准布局类型(3.9),则结果为
静态转换(静态转换(v))
T2的对准要求不比T1严格,或者如果其中一种类型为
void
。将“指针指向T1”类型的PR值转换为“指针指向T2”类型(其中T1和T2是对象类型,T2的对齐要求不比T1严格),然后返回到其原始类型,即可生成原始指针值。未指定任何其他此类指针转换的结果

在您的情况下,由于此层次结构中没有
virtual
方法,因此类型是标准布局类型。由于两者确实具有相同的对齐要求(因为它们包含相同的值),因此我们确实匹配此处明确规定的效果,因此:

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

TL;DR我认为是的,在某些情况下

只要目标类型的对齐要求不比源类型更严格,该保证就应有效。否则,未指定转换的效果


最简单的方法是询问标准,特别是:§5.2.10[expr.reinterpret.cast]

7/对象指针可以显式转换为不同类型的对象指针。70当类型为“指向T1的指针”的PRV值转换为类型为“指向cv T2的指针”时,如果T1和T2都是标准布局类型(3.9),则结果为
静态转换(静态转换(v))
T2的对准要求不比T1严格,或者如果其中一种类型为
void
。将“指针指向T1”类型的PR值转换为“指针指向T2”类型(其中T1和T2是对象类型,T2的对齐要求不比T1严格),然后返回到其原始类型,即可生成原始指针值。未指定任何其他此类指针转换的结果

在您的情况下,由于此层次结构中没有
virtual
方法,因此类型是标准布局类型。由于两者确实具有相同的对齐要求(因为它们包含相同的值),因此我们确实匹配此处明确规定的效果,因此:

#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?
}
-[结束示例]


不幸的是,这个例子是错的(与你的案例相比);所以我们从中得不到多少。我只是为了完整起见才引用它,因为它是相关的。

注意:
new
在这里是无用的;您完全可以在堆栈分配的对象上使用多态性;您完全可以在堆栈分配的对象上使用多态性。
static_cast<I2*>(static_cast<void*>(d))
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.