How to check if a range specified by iterators is valid?
Many of the standard library containers have operations that accept a range specified by iterators. For example, std::list::assign(InputIterator first, InputIterator last)
.
But because many of these operations do not throw exceptions, if the range specified by [first,last)
is not valid, it will cause undefined behaviour.
So what is a valid range? I assume it means that first
comes before or is equal to last
in the container, because when I tried otherwise (i.e. first
comes after last
), the program's execution would hang.
For example:
std::list.assign(container.begin(), container.end()); // valid range
std::list.assign(container.end(), container.begin()); // invalid range
Now with an assumption of what a valid range is, how can we check if a range is valid?
I came up with a helper function that checks if first
is ever equal to last
before it reaches the end of the container. If true, it's a strong guarantee that first
does not come after last
and therefore the range is valid.
template <typename Iterator>
bool isValidRange(Iterator first, Iterator last, Iterator end)
{
for (; first != end; ++first)
if (first == last) return true;
return false;
}
It's not very convenient because you have to pass it an iterator to the end of the container in addition to the iterators that specify the range.
Is this correct? Is there a better way to do this?
Solution 1:
how can we check if a range is valid?
You can't. Your function cannot guarantee that the range is valid, only that the last is reachable from the first. These are two different things (for a simple example, consider an iterator into a vector which was subsequently reallocated). There is no mechanism by Standard that permits you to check if a range is valid. Much like you cannot know that a pointer is valid before you de-reference it.
Just to note, Microsoft provided a function to check if a pointer was valid and it utterly screwed everyone who used it. Raymond Chen said that it should have been named CorruptMemoryIfPossible.