Address one past the end of array - is this syntax a valid C++?

Discussion in 'C++' started by Peter, Feb 1, 2014.

  1. Peter

    Peter Guest

    Assume we have an array:

    int arr[5];

    It's legal to refer to address arr + 5, but, of course, illegal to refer toelement arr[5] as it's not part of the array. However, arr + n is equivalent to &arr[n]. My question is: does this equivalence also hold for an edge case of
    n = 5 (or, generally, n equal to number of elements of array)?

    While there's nothing wrong with arr + 5, &arr[5] looks highly suspicious: it looks like in the first step arr[5] is evaluated (which introduces an undefined behaviour) which would mean the expression as a whole is undefined.Does the equivalence still hold in this special case?
    Peter, Feb 1, 2014
    1. Advertisements

  2. I would not be surprised at the validity of this after I've learned that
    initializing a reference by dereferencing a null pointer is now legal.
    *nullptr creates a special kind of reference, and the only useful
    operation you can do with it is to take its address, which in turn
    should give you null, as I understand it. So, using the same logic, the
    expression a[n] is the same as *(a+n), which is to give you a reference
    to a non-existing element (one beyond the last in the array) and with
    that reference the only valid operation is to take its address.
    According to the precedence rules, &arr[5] is evaluated as &(*(arr+5)),
    which is OK (if you subscribe to the invalid reference idea and the
    validity of applying the 'address of' operator to it).

    Victor Bazarov, Feb 1, 2014
    1. Advertisements

  3. Peter

    bblaz Guest

    Not always true.

    Dereferencing pointers which do not point to valid objects is undefined
    behavior if the program necessitates the lvalue-to-rvalue conversion of
    the *arr expression.
    see 4.1 #1.

    5.3.1 #3
    The result of the unary & operator is a pointer to its operand. The
    operand shall be either an lvalue of type
    other than “array of runtime bound†or a qualified-id.

    Evaluation of &*arr expression does not necessitate the lvalue-to-rvalue
    conversion, hence its legal.

    Also 5.3.1 #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. If the type of the expression is
    “pointer to T,†the type of the result is
    “T.†[ Note: indirection through a pointer to an incomplete type (other
    than cv void) is valid. The lvalue
    thus obtained can be used in limited ways (to initialize a reference,
    for example); this lvalue must not be
    converted to a prvalue, see 4.1. — end note ]

    bblaz, Feb 2, 2014
  4. Peter

    Dombo Guest

    Op 01-Feb-14 23:36, Victor Bazarov schreef:
    I'm not sure this is the case; according to the C++ 11 draft standard
    (N3337): "Note: std::nullptr_t is a distinct type that is neither a
    pointer type nor a pointer to member type; rather, a prvalue of this
    type is a null pointer constant and can be converted to a null pointer
    value or null member pointer value.". I.e. since nullptr is not a
    pointer type the fact that you can legally dereference it (which
    surprised me a bit, but I suppose there is a good reason for it),
    doesn't necessarily mean that it is also legal to dereference a pointer
    referencing a non-existing element.
    Dombo, Feb 2, 2014
  5. Peter

    bblaz Guest

    & is an unary operator & not a reference type. I think your quote is
    irrelevant in this case.

    bblaz, Feb 2, 2014
  6. Peter

    bblaz Guest

    To be clear, i was refering to the op.
    bblaz, Feb 2, 2014
  7. Peter

    James Kanze Guest

    No it's not. They're only equivalent if the expression "arr[n]"
    is a valid expression.
    No. "arr + 5" is legal, and corresponds to a pointer one beyond
    the end of the array. "&arr[5]" is undefined behavior.

    C has a special rule to allow "&arr[5]". Back before C++03 (and
    even before C++98, I think), there was some discussion about
    allowing this in C++, but in the end, the special case was not
    adopted. (I think part of the motivation for not adopting it is
    that you couldn't make it work with user defined containers,
    like std::vector. Something like:

    std::vector<int> v(5);
    int* p = &v[5];

    will crash, at least in debug mode, in all of the
    implementations I use.)
    James Kanze, Feb 14, 2014
  8. Peter

    James Kanze Guest

    Just curious, but where did you get this information from?
    I can't find it in the standard (looking in the obvious places,
    which isn't always enough).
    James Kanze, Feb 14, 2014
  9. I can't give you the exact source, unfortunately, and I am sorry. All I
    can remember is that it was mentioned here, discussed in some thread,
    and at the time my claim of undefined behavior of initializing a
    reference by dereferencing a null pointer was contradicted, and upon
    investigating I found that the lvalue to rvalue conversion that used to
    be necessary and was the cause of the UB in such a case was not any
    longer a requirement (or it was that I incorrectly remembered that
    conversion was needed). And in a blink of an eye, so to speak, UB was
    not there anymore.

    I'm likely too gullible when C++ is concerned. Next you're going to
    tell me that atoi is not a standard function, and I'll believe it. :)

    Victor Bazarov, Feb 14, 2014
  10. Peter

    woodbrian77 Guest

    woodbrian77, Feb 17, 2014
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.