Search code examples
c++language-lawyerundefined-behaviornull-pointerreference-binding

Does forming a reference to an object constitute access?


Does forming a reference to an object constitute access?

Here's what GCC and Clang currently do:

void test(int const volatile* ptr) noexcept {
  *ptr;  // movl (%rdi), eax  // Reads *ptr
  [[maybe_unused]] int const volatile& ref = *ptr;  // Does not read *ptr
}

My question is specifically about the statement

  [[maybe_unused]] int const volatile& ref = *ptr;
  • According to the abstract machine, does this read the value of the object pointed to by ptr?
  • Would this statement, in isolation, be undefined behavior if ptr == nullptr?
  • Would it be an aliasing violation if ptr pointed to something other than an int?

Note that I ask specifically about forming the reference, and not about using it to read the value.

Edit 09/12/2019: Accepting the following answers:

  • Does int const volatile& ref = *ptr; read the value of the pointed-to object?
    • No.
  • Is this undefined when ptr == nullptr?
    • Yes, *ptr on a null pointer is undefined.
  • Is forming the reference an aliasing violation if ptr points to an object of different type?
    • No, just forming the reference does not violate strict aliasing.
    • Presumably reinterpret_cast-ing the reference to the correct type is allowed and valid.

Solution

  • [basic.compound]/3 ... Every value of pointer type is one of the following:

    (3.1) — a pointer to an object or function (the pointer is said to point to the object or function), or

    (3.2) — a pointer past the end of an object (8.7), or

    (3.3) — the null pointer value (7.11) for that type, or

    (3.4) — an invalid pointer value.


    [expr.unary.op]/1 The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points.

    Thus, the meaning of the expression *ptr is only defined for pointer ptr that points to an object or function - that is, a pointer whose value falls under [basic.compound]/(3.1). In all other cases, this expression exhibits undefined behavior.