Preamble: It is well-known that taking the pointer one past the end of an array is legal and well-defined:
int main()
{
int na [1] = {};
const int* naBegin = na;
const int* naEnd = na + 1; // one-past-end, OK
}
This pointer can be used in comparisons, which contributes to C-style arrays (or, more accurately, pointers therein) being compatible with Standard Library routines which take iterators, such as copy
(Live Demo):
template <typename Field, typename Iter>
void foo(Iter begin, Iter end)
{
std::copy (begin, end, std::ostream_iterator <Field> (std::cout, std::endl);
}
int main()
{
int na [1] = {};
foo <int> (na, na + 1);
}
The legality and definedness of this is supported by the Standard (C++03 reference):
5.7 Additive operators
5/When an expression that has integral type is added to or subtracted
from a pointer, the result has the type of the pointer operand. If the
pointer operand points to an element of an array object, and the array
is large enough, the result points to an element offset from the
original element such that the difference of the subscripts of the
resulting and original array elements equals the integral expression.
In other words, if the expression P points to the i-th element of an
array object, the expressions (P)+N (equivalently, N+(P)) and (P)-N
(where N has the value n) point to, respectively, the i+n-th and
i–n-th elements of the array object, provided they exist. Moreover, if
the expression P points to the last element of an array object, the
expression (P)+1 points one past the last element of the array object,
and if the expression Q points one past the last element of an array
object, the expression (Q)-1 points to the last element of the array
object. 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.
When I've looked in the Standard for references to the vlaidity of past-the-end pointers, every reference I've found is discussing arrays. What if we were to try to take past-the-end the address of an object, not an array?
Question: Is it possible to treat a single object, not allocated as an array, as if it were an array and take a valid one-past-the-end address of said object?
For instance (Live Demo):
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <iterator>
template <typename Field, typename Iter>
void foo(Iter begin, Iter end)
{
std::copy (begin, end, std::ostream_iterator <Field> (std::cout, "
"));
}
int main()
{
int na = 42;
foo <int> (&na, &na + 1);
}
Is this code legal and well-defined by the Standard?
See Question&Answers more detail:
os