【发布时间】: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允许的?
【问题讨论】:
-
我认为您还需要分析指针的互转换性(
&j与A*的指针互转换)。 -
没有“联合或类”,因为联合就是类。 :)
-
@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