【发布时间】: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 时,或者
- E 未被潜在评估,或
- 对 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