Is unconditionally creating a pointer to the last element of a vector legal?

124 Views Asked by At

I have the following C++ code:

void bar(int&);
void baz();

void foo(std::vector<int>& v) {
    int* pointer_to_last = v.data() + (v.size() - 1);
    if (v.size() > 0 && *pointer_to_last == 42) {
        bar(*pointer_to_last);
    } else {
        baz();
    }
}

I'm unconditionally creating a pointer to the last element of a vector, but I'm only dereferencing the pointer if the vector is not empty. Is this legal according to the standard or does the code above contain undefined behaviour?

If the above program is legal, is the following program legal as well?

void bar(int&);
void baz();

void foo(std::vector<int>& v) {
    int& reference_to_last = v.back();
    if (v.size() > 0 && reference_to_last == 42) {
        bar(reference_to_last);
    } else {
        baz();
    }
}

The reference for std::vector::back says

Calling back on an empty container causes undefined behavior.

So I'm assuming this program is not legal. Are there any compiler flags for GCC or Clang or any static analyzers that give me a warning for the code above?

2

There are 2 best solutions below

2
HolyBlackCat On

Both are illegal. The former is rejected by UBSAN (aka -fsanitize=undefined) (see [expr.add]/4)

runtime error: applying non-zero offset 18446744073709551612 to null pointer

And the latter is rejected by -D_GLIBCXX_DEBUG:

Error: attempt to access an element in an empty container.

Are there any compiler flags for GCC or Clang

The two above, plus -fsanitize=address.

-D_GLIBCXX_DEBUG is libstdc++-specific. If you use Clang with libc++ instead of libstdc++, then use -D_LIBCPP_ENABLE_DEBUG_MODE. (It seems to require libc++ 17 or newer, their debug mode was broken for a while. It also seems to lack iterator validation. :c)

0
Vlad from Moscow On

According to the C++20 Standard the behavior is undefined (7.6.6 Additive operators)

(4.1) — If P evaluates to a null pointer value and J evaluates to 0, the result is a null pointer value.

(4.2) — Otherwise, if P points to an array element i of an array object x with n elements (9.3.4.5),80 the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i + j of x if 0 ≤ i + j ≤ n and the expression P - J points to the (possibly-hypothetical) array element i − j of x if 0 ≤ i − j ≤ n.

(4.3) — Otherwise, the behavior is undefined