I have a hard time understanding how this code (an example from the C++14 draft standard [conv.lval]) invokes undefined behavior for g(false)
. Why does constexpr
make the program valid?
Also, what does it mean by "does not access y.n
"? In both calls to g()
we are returning the n
data member so why does the last line say it doesn't access it?
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 due to access of x.n outside its
// lifetime
int n = g(true); // OK, does not access y.n
This is because y.n
is not odr-used and therefore does not require an access to y.n
the rules for odr-use are covered in 3.2
and says:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression
Note, Ben Voigt made some helpful comments that clarified this one a bit. So the working assumption here is that x would be:
y
and e would be(the different expression that e is defined for is covered in paragraph 2 of section 3.2):
(b ? y : x).n
y
yields a constant expression and the lvalue-to-rvalue conversion is applied to the expression e.
Since f
yields a lambda which captures f
's local variables by reference x
is no longer valid once the call to f
is done since x
is an automatic variable inside f
. Since y
is a constant expression it acts as if y.n
was not accessed and therefore we don't have the same lifetime issue.
Your example is included in N3939 section 4.1
[conv.lval] and right before that example it says:
When an lvalue-to-rvalue conversion is applied to an expression e, and either
and includes the following bullet which the examle belongs to:
the evaluation of e results in the evaluation of a member ex of the set of potential results of e, and ex names a variable x that is not odr-used by ex (3.2),
then:
the value contained in the referenced object is not accessed
This was applied to the C++14 draft standard due to defect report 1773 .
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With