Search code examples
c++containersstdvector

Why &x[0]+x.size() instead of &x[x.size()]?


I'm reading A Tour of C++ (2nd edition) and I came across this code (6.2 Parameterized Types):

template<typename T>
T* end(Vector<T>& x)
{
     return x.size() ? &x[0]+x.size() : nullptr;     // pointer to one-past-last element 
}

I don't understand why we use &x[0]+x.size() instead of &x[x.size()]. Does it mean that we take the address of the first element in x and just add to that number x.size() bytes?


Solution

  • &x[x.size()] would result in (attempting to) take the address of x[x.size()]. However x[x.size()] attempts to access an out of bound element; depending on the API of Vector<T>::operator[] for the particular T, a number of bad things could happen:

    |    Vector<T>::operator[] semantics      |
    | ======================================= |
    | return\ contr |             |           |
    | type   \ -act |  unchecked  |  checked  |
    | --------------------------------------- |
    | reference     |    UB (1)   |    FH     |
    | value         |    UB (2)   |    FH     |
    | --------------------------------------- |
    

    with

    • UB (1): undefined behavior when creating a reference to an out-of-range-element.
    • UB (2): undefined behaviour when attempting to read the value of an out-of-range element.
    • FH: some fault handling action from the API if it is checked (e.g. throwing an exception, terminating, ...).

    For std::vector, as an example, you would run into UB (1) as its operator[] is unchecked and returns a reference type.

    Whilst you may perform pointer arithmetics to compute a pointer to one-past-last (semantically end()) of a buffer, you may not dereference a one-past-last pointer.