Dr.*_*Gut 5 c++ strict-aliasing undefined-behavior language-lawyer reinterpret-cast
假设我们有两种类型,它们具有相同的表示形式(相同的成员变量和基类,顺序相同)。它们之间是否有效(即不是 UB)reinterpret_cast?例如,reinterpret_cast从Mary到有效吗Ashley&?如果这两种类型是多态的怎么办?
struct Mary {
int m1;
char m2;
};
struct Ashley {
int a1;
char a2;
};
int TryTwins ()
{
Mary mary = {};
Ashley& ashley = reinterpret_cast<Ashley&> (mary);
ashley.a1 = 1;
ashley.a2 = 2;
return mary.m1 + mary.m2;
}
Run Code Online (Sandbox Code Playgroud)
如果我们知道源类型以目标类型的成员变量开头,那么我们将对象的开头强制转换为另一种类型会怎样?例如,这有效吗(即不是 UB)?
struct Locomotive {
int engine;
char pantograph;
};
struct Train {
int engine;
char pantograph;
int* wagon1;
int** wagon2;
int*** wagon3;
};
int TryTrain ()
{
Train train = {};
Locomotive& loc = reinterpret_cast<Locomotive&> (train);
loc.engine = 1;
loc.pantograph = 2;
return train.engine + train.pantograph;
}
Run Code Online (Sandbox Code Playgroud)
请注意,所有主要编译器都将这些视为有效的强制转换(现场演示)。问题是,C++语言是否允许这样做。
\n\n\n\n
T1如果可以显式转换\xe2\x80T2\x9c 类型的表达式,则可以将 \xe2\x80\x9creference\n 类型的泛左值表达式强制T1转换为 \xe2\x80\x9d 类型的指针到 \xe2\x80\x9d指向类型 \xe2\x80\x9cT2使用 指向 \xe2\x80\x9d 的指针reinterpret_\xc2\xadcast。\n 结果引用与源泛左值相同的对象,但具有指定的类型。[...]
Mary和Ashley是对象类型,因此指向它们的指针可以相互转换。现在,我们可以使用类型的左值Ashley来访问底层Mary对象。
\n\n\n如果程序尝试通过以下类型之一以外的泛左值访问对象的存储值,则行为未定义:
\n\n\n
\n- \n
对象的动态类型,
- \n
对象动态类型的 cv 限定版本,
- \n
类似于对象的动态类型的类型,
- \n
与对象的动态类型相对应的有符号或无符号类型,
- \n
与对象动态类型的 cv 限定版本相对应的有符号或无符号类型,
- \n
聚合或联合类型,其元素或非静态数据成员中包含上述类型之一(递归地包括子聚合或包含的联合的元素或非静态数据成员),
- \n
是对象动态类型的(可能是 cv 限定的)基类类型的类型,
- \n
a
char、unsigned char、 或std\xe2\x80\x8b::\xe2\x80\x8bbyte类型。
这些都不涵盖所讨论的情况。(“类似”谈论简历资格。)因此,未定义的行为。
\n