The convention for ranges is [inclusive, exclusive)
, that is if you iterate over a range [X,Y)
you will conceptually do the following (pseudo-code):
for( iterator ii = X; ii != Y; ++ii) {
...
}
This permits to express an empty range as [X,X)
. Also this empty range is perfectly well defined for each address, no matter if it is valid or invalid.
That said the requirements for data()
are (emphasis mine):
23.3.6.4 [vector.data]
T* data() noexcept;
const T* data() const noexcept;
Returns: A pointer such that [data(),data() + size()) is a valid range. For a
non-empty vector, data() == &front().
It seems to me that the only unconditional guarantee is that [data(),data() + size())
should be a valid range. For size() == 0
the member function data()
may return any value and the range will be a valid empty range. Therefore I would say that an implementation is allowed to return a non-null pointer if size()
is zero.