Question

I need to be able to access (read-only, no resizing involved or anything like that) the elements of a an std::vector via pointers. E.g.,

std::vector<int> foo(10);
int *ptr_begin = &foo[0];

So far so good, this is guaranteed to work in the current standard (23.3.6.1):

The elements of a vector are stored contiguously, meaning that if v is a vector where T is some type other than bool, then it obeys the identity &v[n] == &v[0] + n for all 0 <= n < v.size().

So we can access all elements of the vector using pointers, since they are stored in a contiguous chunk of memory. But what about the one-past-the-last element? I mean, it is legal to perform this operation?

int *ptr_end = ptr_begin + foo.size()

(Note, I am not trying to access the past-the-last value, merely to define a pointer to it - an equivalent to foo.end() if you like). The standard mentions only accessing elements via pointer arithmetics, but clearly here we are not accessing any element.

(As a side note, the definition of the existence of a past-the-last something seems tightly connected to the base concept of array (see for instance 5.7/5), but throughout the standard it seems like the concepts of contiguous storage and array are used interchangeably. Am I reading wrong?)

Was it helpful?

Solution

Yes, as long as you only use ptr_end in comparisons* and don't attempt to deference it, this is fine. Quoting from § 5.7 in the C++11 draft standard regarding additive operations with pointers (emphasis mine):

If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.

Similar provisions are listed for the relational operators in § 5.9:

If two pointers point to elements of the same array or one beyond the end of the array, the pointer to the object with the higher subscript compares higher.

As to whether vector's buffer counts as an array for the purposes of the above, § 8.3.4 states:

An object of array type contains a contiguously allocated non-empty set of N subobjects of type T.

which is consistent with what § 23.3.6.1 has to say about vector:

The elements of a vector are stored contiguously


Since pointers are iterators, this sort of thing is a handy trick for using standard library algorithms with an arbitrary block of memory as the input. For example, say you want to use the lower_bound algorithm, but your data is stored in an MFC CArray:

CArray<int> someInts;
// populate and check for empty
int* begin = someInts.GetData();
int* end = begin + someInts.GetSize(); // for bounds-checking only; don't dereference
int* answer = std::lower_bound(begin, end, 100);

*There are a couple other operations that are legal too; e.g. since you know your vector isn't empty, you could subtract one to get a pointer to the last element. The important thing is don't dereference.

OTHER TIPS

You should remember about existence of std::vector::data(), which explicitly gives you the pointer to this continuous memory. So yes, read only operations are available (if you're not mixing them with other vector methods, which could do some reallocation etc. underneath).

I would even go further - changing contents of memory under std::vector::data() should also be legal.

Yep, it is legal to form the address to the one-past-the-end element. It is not legal to deference it. The draft standard even has a footnote which notes that "an implementation need only provide one extra byte (which might overlap another object in the program) just after the end of the object in order to satisfy the “one past the last element” requirements". You are also allowed to do pointer math with it (at least all of the legal stuff that you could do if you were dealing with a pointer into the array).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top