In the C ++ 14 standard (n3797), the section on converting lvalue to rvalue is read as follows (emphasis is mine):
4.1 Converting Lvalue-to-r [conv.lval]
The value gl (3.10) of a non-function type without an array T can be converted to prvalue. If T is an incomplete type, a program that requires this conversion is poorly formed. If T is a non-class type, the prvalue type is a cv-unqualified version of T Otherwise, the prvalue type will be T
When the conversion lvalue-rvalue occurs in an unvalued operand or its subexpression (paragraph 5), the value contained in the reference object is not available. In all other cases, the result of the transformation is determined in accordance with the following rules:
- If
T is (possibly cv-qualified) std::nullptr_t , then the result is a null pointer constant. - Otherwise, if
T is of class type, the copy of the conversion initializes the temporary type of T from the glvalue, and the result of the conversion is the prvalue for the temporary. - Otherwise, if the object to which the glvalue reference refers contains an invalid pointer value, the behavior is determined by the implementation.
- Otherwise, if
T is a (possibly cv-qualified) type of unsigned character, and the object to which the glvalue reference refers contains an undefined value, and this object does not have automatic storage duration or the value of the glvalue operand of the unary operator & or it is bound to reference, the result is an undefined value. - Otherwise, if the object to which the glvalue belongs has an undefined value, the behavior is undefined.
- Otherwise, the object indicated by glvalue is the result of prvalue.
- [Note: see also 3.10]
What is the meaning of this paragraph (in bold)?
If this paragraph was not here, then the situations in which it is applied will lead to undefined behavior. Normally, I would expect that accessing an unsigned char value when it has an undefined value will result in undefined behavior. But in this paragraph, this means that
- If I really don’t get access to the value of the symbol, that is, I immediately pass it to
& or binding it to a link, or - If
unsigned char does not have automatic storage duration,
that conversion gives an undefined value, not undefined behavior.
Do I conclude correctly that this program:
#include <new> #include <iostream> // using T = int; using T = unsigned char; int main() { T * array = new T[500]; for (int i = 0; i < 500; ++i) { std::cout << static_cast<int>(array[i]) << std::endl; } delete[] array; }
well defined by the standard and should output a sequence of 500 unspecified ints, while the same program, where T = int , would have undefined behavior?
IIUC, one of the reasons forcing UB to read things with undefined values, is to allow the optimizer to aggressively destroy dead storage. Thus, this paragraph may mean that the corresponding compiler cannot do as much optimization when working with unsigned char or unsigned char arrays.
Assuming I understand correctly, what is the meaning of this rule? When is it useful to read unsigned char with undefined values and get unspecified results instead of UB? I have the feeling that if they did their best to develop this part of the rule, they had some motivation to help some of the code examples that they cared for, or to comply with some other part of the standard, or to simplify some other problems, But I have no idea what it could be.
c ++ undefined-behavior language-lawyer c ++ 14 lvalue-to-rvalue
Chris beck
source share