通过类型错误的指针调用方法?合法吗?

时间:2018-11-30 14:32:10

标签: c++ casting type-conversion language-lawyer

该标准在示例 2 中告诉我们 1 ,以下内容是合法的:

struct T1 { int a, b; };
struct T2 { int c; double d; };
union U { T1 t1; T2 t2; };
int f() {
  U u = { { 1, 2 } };   // active member is t1
  return u.t2.c;        // OK, as if u.t1.a were nominated
}

现在,添加一个间接级别(成员函数)并删除另一个(成员),我想知道:

以下定义是否明确?

struct T1      { int a; int value() { return a; }};
struct T2 : T1 { int b; };
int f() {
  T1 t1 = { 1 };
  return reinterpret_cast<T2*>(&t1)->value();
}

我知道演员表本身不是不确定的行为 3 ;但是->运算符的结果是否侵犯了[basic.lval]/11 4 ?还是由[expr.ref]/4 5 保存?

我想认为这是合法的,因为t1.areinterpret_cast<T2*>(&t1)->a具有相同的地址 6 (因此其表示中的偏移量相同) 。但是吗?


1) [class.mem]/22[class.mem]/23定义什么是与布局兼容的类[class.mem]/25给了我们:

  

在结构类型为T1的活动成员的标准布局联合中,允许读取结构类型为{{的另一个联合成员的非静态数据成员m 1}},前提是T2mT1共同初始序列的一部分;行为就好像T2的相应成员已被提名。

2)[class.mem]/25中。

3) [expr.reinterpret.cast]/7

  

可以将对象指针显式转换为其他类型的对象指针。将对象指针类型的prvalue v转换为对象指针类型“指向T1的指针”时,结果为cv T

[expr.static.cast]/13

  

可以将“指向 cv1 static_­cast<cv T*>(static_­cast<cv void*>(v))的指针的prvalue转换为”指向 cv2 void的指针的prvalue,其中T是对象类型,而 cv2 是与 cv1 相同的cv限定,或具有更大的cv限定。如果原始指针值表示存储器中字节的地址T,并且A不满足A的对齐要求,则未指定结果指针值。否则,如果原始指针值指向对象T,并且存在类型为a(忽略cv限定)的对象b,该指针可以与{{1}进行指针转换},结果是指向T的指针。否则,转换后指针值将保持不变。

4) [basic.lval]/11

  

如果程序尝试通过以下类型之一以外的glvalue访问对象的存储值,则行为未定义:

     
      
  • [不适用规则]
  •   
  • (11.6)聚合或联合类型,其元素或非静态数据成员(包括递归地包括子聚合或所包含的联合的元素或非静态数据成员)中包括上述类型之一, li>   
  • [不适用规则]
  •   

5) [expr.ref]/4,涉及包含符号ab的后缀表达式。

6) [class.mem]/26

  

如果 standard-layout类对象具有任何非静态数据成员,则该对象的地址与其第一个非静态数据成员的地址相同(如果该成员不是位字段) 。其地址也与其每个基类子对象的地址相同。

1 个答案:

答案 0 :(得分:2)

不,据我所知是UB。

我看不到[expr.ref] p4如何拯救您。您正在通过其他类型的指针(也不是对象的动态类型)访问T1类型的对象。

此外,[class.mem] p26不相关,因为您已经违反了[basic.lval] p11。