how can I check for a bad iterator

This is a discussion on how can I check for a bad iterator within the C++ Programming forums, part of the General Programming Boards category; Hi, I'm doing some stuff with iterators in my code. I occasionally run into problems with a global iterator being ...

  1. #1
    Registered User
    Join Date
    Mar 2003
    Posts
    25

    how can I check for a bad iterator

    Hi,

    I'm doing some stuff with iterators in my code. I occasionally run into problems with a global iterator being set in one place and used somewhere else. Most of the time it works properly, but due to some circumstances of the program it fails sometimes. This is probably bad design but I don't have time to change it at this point. The problem is with this:

    Code:
    if (selectionCount == 1) {
    	itDownRectangle->setSelected(false);
    	selectionCount--;
    }
    I've been doing Java for a while and would normally do something like this,

    Code:
    if (selectionCount == 1 && itDownRectangle != null) {
    	itDownRectangle->setSelected(false);
    	selectionCount--;
    }

    But comparing to NULL in this case gives compile errors about unable to convert from NULL to and iterator, since NULL is a pointer to 0. How can I check for this in C++ to avoid runtime errors?

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,796
    >But comparing to NULL in this case gives compile errors
    An iterator isn't necessarily a pointer, though it could be.

    >How can I check for this in C++ to avoid runtime errors?
    There are two kinds of invalid iterator. First is the "past the end" iterator where you test it against your container's end member function:
    Code:
    if ( iter != container.end() ) {
      // Okey dokey
    }
    The second is a truly invalid iterator, and barring some rather nasty code that I wouldn't be caught dead posting, you're SOL if it happens. But that's very likely a severe design flaw in your code that should be fixed anyway, so testing for it is a moot point.
    My best code is written with the delete key.

  3. #3
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,893
    In Java, testing an iterator against null accomplishes exactly nothing. If concurrent modification occurs (the only way to invalidate a Java iterator), it tries to throw a ConcurrentModificationException, but the emphasis is on tries: it might also just return more or less random results.

    So what you want to do doesn't actually work in Java.

    In C++, the situation is even worse, because a) you have many more options for invalidating an iterator and b) the consequences are far more interesting. (As in, harder to detect, more severe in consequence.)

    Beyond testing against container.end(), there's really nothing you can do. An iterator pointing anywhere but the sequence or one-past-the-end is useless and more or less undetectable. (You could iterate through the container and compare the iterator at each point with the one you have. If none compares equal, you iterator is invalid.)
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  4. #4
    Registered User
    Join Date
    Mar 2003
    Posts
    25
    well, you're right, my Java example was more along the lines of how you can compare anything to null (except for the primitives). But here's another question which my resolve this issue altogether. Let's say I have this code (well nevermind, I do have this code...)

    Code:
    for (vector<Rectangle>::iterator itRect = it->getRectangles()->begin(); itRect != it->getRectangles()->end(); itRect++) {
    	// find the particular rectangle that we are in
    	if (itRect->isPointInRectangle(&downPoint)) {
    		itRect->setSelected(true);
    		itDownRectangle = itRect; // line x
    		selectionCount++;
    		break;
    	}
    }
    Now my original thinking which I would still like to accomplish somehow is:

    The itDownRectangle in line x is decalred as:
    Code:
    static vector<Rectangle>::iterator itDownRectangle;
    What I really wanted to do, but my lack of expertise in C++ prevented me from was:
    Code:
    static Rectangle * downRectangle;
    and then
    Code:
    // new line x
    downRectangle = itRect; // rather the pointer the itRect points to
    I tried several variations of the above code but gave up, correct me if I'm wrong but this would make a copy instead of just another reference to the same object?
    Code:
    *downRectangle = *itRect;
    I think I tried it like that originally but because it was a copy, it was kind of useless to me. Anything else I tried resulted in compiler errors so that was no good either. So forget about checking the iterator, how can I get a pointer to the object the iterator is currently pointing to? Then I should be able to compare to NULL right? That would be the ideal situation.

    Thanks

  5. #5
    Registered User
    Join Date
    Jan 2005
    Posts
    7,344
    You have to dereference the iterator to get the object: (*itRect). You can initialize a reference with that, or take its address (with &) and assign that to a pointer.

    In this case those are both still bad solutions, because a reference or pointer can be invalidated just like an iterator can when your vector holds Rectangle objects. As a Java programmer, you might be more comfortable using a vector<shared_ptr<Rectangle> >. That is much more like the Java equivalent would be. Otherwise, I would store an index and not a pointer to the object. If the indexes change, then use the shared_ptr version or create another class that keeps track of the Rectangles via some unique and consistent ID.

    >> Then I should be able to compare to NULL right? That would be the ideal situation.
    In general, if something were to invalidate the object (say for example you removed it from the vector), then this wouldn't work because nothing will automatically update the pointers lying around to indicate that the object had been removed. In this case it is even worse because even if the Rectangle isn't touched, the vector can move stuff around and invalidate the pointer. You have to manually update all references to the object when it changes unless you use a class (like shared_ptr or weak_ptr) that does it for you.
    Last edited by Daved; 10-23-2006 at 06:37 PM.

  6. #6
    Registered User
    Join Date
    Sep 2001
    Posts
    752
    What you are asking for can't really be done as asked. While you could technically probably get away with
    Code:
    itDownRectangle = &(*currRect)
    There's no gaurantee that the vector will not move its memory around later during the program, invalidating the pointer.

    Really, to properly do what you're asking, you're gonna have to do it Java-style.... use a vector of pointers instead of a vector of Rectangles.
    Code:
    for (vector<Rectangle *>::iterator itRect = it->getRectangles()->begin(); itRect != it->getRectangles()->end(); itRect++) {
    	Rectangle * & currRect = *itRect; // To make typing easier
    
    	// find the particular rectangle that we are in
    	if (currRect->isPointInRectangle(&downPoint)) {
    		currRect->setSelected(true);
    		itDownRectangle = currRect; // line x
    		selectionCount++;
    		break;
    	}
    }
    Callou collei we'll code the way
    Of prime numbers and pings!

  7. #7
    Registered User
    Join Date
    Mar 2003
    Posts
    25
    hmm... this looks interesting. I may give that one a try. I wish I had more time to work on this... at least I'm learning more C++ I had the option to do this assignment in Java but I wanted to get more experience with C++.

  8. #8
    Registered User
    Join Date
    Jan 2005
    Posts
    7,344
    A container of raw pointers works fine, but a container of shared_ptr's is better, especially if you really want to practice doing it "the right way". This solution is extra good because I believe you can use a weak_ptr for the downRectangle and you can check it for validity before using it. If you're short on time then maybe the shared_ptr/weak_ptr solution will be too high of a learning curve.

    If you do use raw pointers, make sure you pay attention to memory management like deleting your memory when necessary.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Big help in Astar search code...
    By alvifarooq in forum C++ Programming
    Replies: 6
    Last Post: 09-24-2004, 12:38 PM
  2. Help with defining an iterator class
    By Dragoon_42 in forum C++ Programming
    Replies: 2
    Last Post: 02-04-2003, 06:26 PM
  3. Shocking(kind of)
    By Shadow in forum A Brief History of Cprogramming.com
    Replies: 25
    Last Post: 12-10-2002, 08:52 PM
  4. Search and Build Tree
    By 1999grandamse in forum C++ Programming
    Replies: 17
    Last Post: 11-14-2002, 01:36 PM
  5. UNICODE and GET_STATE
    By Registered in forum C++ Programming
    Replies: 1
    Last Post: 07-15-2002, 04:23 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21