【问题标题】:An issue about the example after [conv.lval#2.2]关于 [conv.lval#2.2] 之后示例的问题
【发布时间】:2020-12-14 05:02:40
【问题描述】:

例子是:

struct S { int n; };
auto f() {
S x { 1 };
constexpr S y { 2 };
return [&](bool b) { return (b ? y : x).n; };
}
auto g = f();
int m = g(false);   // undefined behavior: access of x.n outside its lifetime
int n = g(true);    // OK, does not access y.n

相关规则为:

当左值到右值的转换应用于表达式 E 时,或者

  1. E 未被潜在评估,或
  2. 对 E 的评估导致对 E 的潜在结果集合中的成员 Ex 的评估,和 Ex 命名一个变量 x,它不被 Ex([basic.def.odr]) 使用

被引用对象中包含的值未被访问。

我怀疑 y.n 的表达方式,它被认为是 n 的非 odr-used。

根据规则:

表达式 E 的潜在结果集定义如下:

  • 如果 E 是 id 表达式 ([expr.prim.id]),则该集合仅包含 E。
  • [...]
  • 如果 E 是 E1 形式的类成员访问表达式 ([expr.ref])。模板opt E2 命名一个非静态数据成员集合包含E1的潜在结果子>。

根据项目符号 3,表达式y.n 的潜在结果是y 本身,而n 确实是y 的成员,这是y.n 的潜在结果。但是,我不同意n 不是odr-used

根据这条规则:
basic.def.odr#4.2

名称显示为潜在求值表达式 E 的变量 x 被 E 直接使用,除非

  • x 是非引用类型的变量,可用于常量表达式且没有可变子对象,E 是非易失性限定的非类表达式的潜在结果集合中的一个元素应用左值到右值转换 ([conv.lval]) 的类型

左值到右值的转换应用于表达式y.n,其潜在结果仅包含对象表达式y,而不是n。因此,根据 [basic.def.odr#4.2],名为 n 的变量由表达式 n 使用。所以,g(true) 应该是未定义的行为。如何解释这个例子?这是一个错误的例子吗?

【问题讨论】:

  • n 不包含在(b ? y : x).n 的潜在结果集中,因此 odr-use 根本不能适用于它。
  • @LanguageLawyer 是的,我知道。我的误解是,对 E 的评估导致对 E 的一组潜在结果中的 成员 Ex 的评估。我认为 E 的潜在结果(y 或 x)的成员数据。
  • 而且S::n毕竟不是变量。
  • @LanguageLawyer 你的意思是,因为S::n 不是一个对象,所以它不是每个basic#6 的变量,对吧?
  • s.n 是一个对象,但n 仍然不是一个变量

标签: c++ language-lawyer


【解决方案1】:

你的推理问题是[conv.lval]/3.2 不要求 n 不被使用。有问题的表达式是E = (b ? y : x).n。潜在结果集是{x, y}。对E 的评估,当b = true 时,最终将导致对y 的评估。因此,我们可以设置E<sub>x</sub> = y,我们现在发现“E 的评估导致E 的潜在结果集合中的成员E<sub>x</sub> 的评估”是一个真实的陈述。该子句现在只要求E<sub>x</sub> = y 命名一个在E<sub>x</sub> 中未使用的变量。让我重复一遍,因为我认为这是你出错的地方:[conv.lval]/3.2 询问E<sub>x</sub> odr-uses itself(或者,实际上是它命名的变量)。我们正在寻找的东西是证明表达式y 不使用变量y 的证据。 n 的成员访问权限无关紧要。

好吧,我们继续看[basic.def.odr]/4

变量x 的名称显示为潜在评估表达式EE 使用 除非

  • ...
  • x 是非引用类型的变量,可用于常量表达式并且没有可变子对象,E 是非易失性限定的非类类型表达式的潜在结果集合中的一个元素应用了左值到右值的转换 ([conv.lval]),或者
  • ...

请注意,这里的E 不是我们在[const.lval]/3.2 中开始使用的E = (b ? y : x).nE 是我们正在测试 y 的 odr 使用的表达式。让我们将其命名为E'。然后是E' = E<sub>x</sub> = y,因为我们再次检查表达式y odr 是否使用变量y。条件的第一部分成立; y 是一个非引用类型的变量,可用于常量表达式,它没有可变的子对象。现在,E' = y 是原始E 的潜在结果集的元素(因为E 是应用左值到右值转换的非易失性限定非类类型的表达式) ?是的,我们已经讨论过了,yE 的潜在结果之一。因此,E<sub>x</sub> 不使用 y。这完成了[conv.lval]/3.2 的前提条件:我们现在知道(b ? y : x).n 在评估左值到右值转换时不会访问值y.n。因此,没有UB。同样,请注意n 在我们的推理中根本没有出现。

【讨论】:

  • E( (b ? y : x).n ) 的潜在结果集是(b? x: y) 的潜在结果集,根据basic.def.odr#2.7,反过来,潜在结果结果是yx。所以,(b?y:x).n) 的潜在结果集是 {y,x},对吧?语句“E 的评估导致 E 的潜在结果集的成员 Ex 的评估”只需要 xy 不是 odr-used 的相应表达式。根据我对 [basic.def.odr#4.2] 的理解,y 没有使用名为 y 的变量。
猜你喜欢
  • 2016-01-17
  • 1970-01-01
  • 1970-01-01
  • 2016-01-15
  • 2011-10-12
  • 2020-08-03
  • 1970-01-01
  • 2022-10-01
  • 1970-01-01
相关资源
最近更新 更多