Checking If an Iterator Is Valid

Checking if an iterator is valid

I assume you mean "is an iterator valid," that it hasn't been invalidated due to changes to the container (e.g., inserting/erasing to/from a vector). In that case, no, you cannot determine if an iterator is (safely) dereferencable.

Is there any way to check if an iterator is valid?

std::maps are not at all thread-safe. You'll end up with much worse problems than invalidated iterators, if you have more than one thread at a time modifying the same map. I don't even think you have a guarantee that you can read anything out of a map while it's being modified by another thread.

Some pages on the STL and threading:

  • MSDN
  • SGI
  • GCC

How to check if the iterator is initialized?

I managed to find this in the current standard (c++03 ). 24.1 p 5 tells :

Just as a regular pointer to an array guarantees that there is a
pointer value pointing past the last element of the array, so for any
iterator type there is an iterator value that points past the last
element of a corresponding container. These values are called
past-the-end values. Values of an iterator i for which the expression
*i is defined are called dereferenceable. The library never assumes
that past-the-end values are dereferenceable. Iterators can also have
singular values that are not associated with any container.
[Example:
After the declaration of an uninitialized pointer x (as with int* x;),
x must always be assumed to have a singular value of a pointer. ]
Results of most expressions are undefined for singular values; the
only exception is an assignment of a non-singular value to an iterator
that holds a singular value.
In this case the singular value is
overwritten the same way as any other value. Dereferenceable values
are always non- singular.

(Emphasis mine)

So the answer is : no, it is not possible.

Testing whether an iterator points to the last item?

Do this:

// defined in boost/utility.hpp, by the way
template <typename Iter>
Iter next(Iter iter)
{
return ++iter;
}

// first check we aren't going to kill ourselves
// then check if the iterator after itr is the end
if ((itr != Mine.end()) && (next(itr) == Mine.end()))
{
// points at the last element
}

That is all. Never gives you undefined behavior, works on all iterators, good day.

Wrap it up for fun:

template <typename Iter, typename Cont>
bool is_last(Iter iter, const Cont& cont)
{
return (iter != cont.end()) && (next(iter) == cont.end())
}

Giving:

if (is_last(itr, Mine))

If you're allergic to utility functions/nice looking code, do:

if ((itr != Mine.end()) && (itr + 1 == Mine.end()))

But you can't do it on non-random-access iterators. This one works with bidirectional iterators:

if ((itr != Mine.end()) && (itr == --Mine.end()))

And is safe since end() > itr by the first check.

Can I check a C++ iterator against null?

You don't need to check if the iterator is null, because it will never be. You need to check if the returned iterator is different from the container's end() position. If it is, you can safely dereference the iterator by *it.

If the container is empty, the returned iterator value shall not be dereferenced.
So if I have an empty container, vector::end() and vector::begin() point to the same place, I don't think I can dereference it, and I'm not even sure it's pointing to allocated memory.

No, checking if(myIt != container.end()) is not dereferencing the iterator. Iterator dereferencing is done via *myIt, which means getting the value of the object that the iterator is pointing to. It's always safe to check iterators to other iterators from the same container, it's unsafe to dereference iterators not pointing to containers' elements.

How to check if a range specified by iterators is valid?

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.

Check if an iterator is valid for a QT container

No. The whole point of iterators is that they are independent of any containers. It is up to you to ensure that you only mutate a container if nobody else still has any iterators or references to the container's elements (subject to the container's iterator/reference invalidation specification).

How to check if a template parameter is an iterator type or not?

template<class T>
struct is_iterator
{
static T makeT();
typedef void * twoptrs[2]; // sizeof(twoptrs) > sizeof(void *)
static twoptrs & test(...); // Common case
template<class R> static typename R::iterator_category * test(R); // Iterator
template<class R> static void * test(R *); // Pointer

static const bool value = sizeof(test(makeT())) == sizeof(void *);
};

Do STL iterators guarantee validity after collection was changed?

Depends on the container. e.g. if it's a vector, after modifying the container all iterators can be invalidated. However, if it's a list, the iterators irrelevant to the modified place will remain valid.

  • A vector's iterators are invalidated when its memory is reallocated. Additionally, inserting or deleting an element in the middle of a vector invalidates all iterators that point to elements following the insertion or deletion point. It follows that you can prevent a vector's iterators from being invalidated if you use reserve() to preallocate as much memory as the vector will ever use, and if all insertions and deletions are at the vector's end. [1]

  • The semantics of iterator invalidation for deque is as follows. Insert (including push_front and push_back) invalidates all iterators that refer to a deque. Erase in the middle of a deque invalidates all iterators that refer to the deque. Erase at the beginning or end of a deque (including pop_front and pop_back) invalidates an iterator only if it points to the erased element. [2]

  • Lists have the important property that insertion and splicing do not invalidate iterators to list elements, and that even removal invalidates only the iterators that point to the elements that are removed. [3]

  • Map has the important property that inserting a new element into a map does not invalidate iterators that point to existing elements. Erasing an element from a map also does not invalidate any iterators, except, of course, for iterators that actually point to the element that is being erased. [4] (same for set, multiset and multimap)



Related Topics



Leave a reply



Submit