【问题标题】:Could we access member of a non-existing class type object?我们可以访问不存在的类类型对象的成员吗?
【发布时间】:2019-04-08 15:26:05
【问题描述】:

在 c++ 标准中,[basic.lval]/11.6 中说:

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

  • 一种聚合或联合类型,在其元素或非静态数据成员(递归地包括子聚合或包含联合的元素或非静态数据成员)中包含上述类型之一,[...]

这句话是严格别名规则的一部分。

它允许我们通过类成员访问别名吗?

class A{ //"casted to" aggregate
  int i;
  float g;
  };

int j=10;
int l = reinterpret_cast<A*>(&j)->i;

根据标准,对象值只有在对象经过lvalue-to-rvalue-conversion[conv.lval]/2时才会被访问。

[expr.ref] 没有规定 object-expression 必须引用该类型的对象,只是规定 glvalue 必须具有类类型(object-expression是点“.”左边的表达式)。然而,有一个词经常出现在与成员访问相关的句子中,这可能意味着对我忽略的程序的限制。例如[expr.ref]/4.1:

如果E2是一个静态数据成员并且E2的类型是T,那么E1.E2是一个左值;表达式指定类的命名成员。

“指定”是否意味着该成员在其生命周期内,并且我不能使用类成员访问来执行别名?还是[basic.lval]/11.6允许的?

【问题讨论】:

  • 我认为您还需要分析指针的互转换性(&amp;jA* 的指针互转换)。
  • 没有“联合或类”,因为联合就是类。 :)
  • @geza:恰恰相反——由于问题被标记为language-lawyer,因此必须仔细阅读,仔细的读者会注意到“类”包括工会,除非另有限定。
  • 我必须再考虑一下,但我相信它旨在支持的案例是我在my strict aliasing answer here 中为该段落提供的示例。另请参阅paper I reference here
  • [basic.lval]/11.6 是否定规则。 “如果你做 X,行为是未定义的”并不意味着“如果你不做 X,行为是被定义的”。那是denying the antecedent

标签: c++ language-lawyer strict-aliasing class-members


【解决方案1】:

对于非静态数据成员,字为:

如果 E2 是非静态数据成员并且 E1 的类型是“cq1 vq1 X”,并且 E2 的类型是“cq2 vq2 T”,则表达式指定 对象的命名成员 由第一个表达式指定。

显然*reinterpret_cast&lt;A*&gt;(&amp;j)指定的对象,即j,没有成员,所以行为是undefined by omission

【讨论】:

  • 在许多情况下,标准的某些部分会暗示某些操作的行为,而没有其他部分表示重叠类的操作会调用 UB。传递地应用&amp;structPtr-&gt;firstMember(*firstMemberType)structPtr 以及*&amp;intLvalueintLvalue 的等价性就足以暗示((structType*)&amp;intObject)-&gt;firstMember 应该如何工作,所以我不会认为这样的构造是“未定义的遗漏”。
猜你喜欢
  • 2019-04-08
  • 2021-12-11
  • 2017-01-16
  • 1970-01-01
  • 1970-01-01
  • 2020-12-24
  • 1970-01-01
  • 2011-08-11
  • 2019-04-08
相关资源
最近更新 更多