|
-
February 22nd, 2008, 06:42 AM
#1
An intelligent iterator for std::list
Code:
typedef std::list<int> intList;
typedef intList::iterator myListIter;
intList myList;
myListIter iter = myList.begin();
while (1)
{
if (iter == myList.end())
{
myList.push_back(2);
myList.push_back(4);
myList.push_back(6);
}
}
On the first time round the loop, myList is empty. On the second time round, 3 items have been added to the list. Therefore 'iter' is no longer at the list end. However, the test if (iter == myList.end()) passes, so 3 more ints get added to the list.
Is there a way to 'reset' an iterator (or to have some kind of intelligent iterator) so that, if items get added to (or removed from) the list, the iterator keeps track of the new begin() and end() ?
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
February 22nd, 2008, 07:02 AM
#2
Re: An intelligent iterator for std::list
An iterator is implemented as some kind of pointer to an element. It does not change when new items are added/deleted. The pointer is constant. YOu will have to assign new values to your iterator:
Code:
iter = myList.begin();
Laitinen
-
February 22nd, 2008, 07:31 AM
#3
Re: An intelligent iterator for std::list
But surely myList.end() should be returning the modified end point - not the original end point.
Something's wrong here - either myList.end() is returning the wrong element or iter is somehow getting updated as elements get added.
What I need is an iterator that remembers where it was - even if new elements get added (which doesn't seem to be what's happening).
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
February 22nd, 2008, 08:13 AM
#4
Re: An intelligent iterator for std::list
 Originally Posted by John E
What I need is an iterator that remembers where it was - even if new elements get added (which doesn't seem to be what's happening).
All iterators supplied by the standard library are are becoming invalid if new items are added. Using them is undefined behaviour (as you can see with your example, which might work different with different c++ compilers). If you want a different kind of iterator, you have to implement it yourself.
EDIT: Just some thought: I assume, the "surprising" results you get, are caused by the implementation returning a kind-a-null-pointer (TM) as list::end(). So list::begin() on an empty list will return list::end(), i.e. this kind-a-null-pointer. The push-back's do of course not affect this, so your check if the iterator is still pointing to end() will always be true. But as stated, this is just the undefined behaviour of your specific impelementation...
Last edited by treuss; February 22nd, 2008 at 08:22 AM.
More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity. --W.A.Wulf
Premature optimization is the root of all evil --Donald E. Knuth
Please read Information on posting before posting, especially the info on using [code] tags.
-
February 22nd, 2008, 08:23 AM
#5
Re: An intelligent iterator for std::list
Originally Posted by treuss
All iterators supplied by the standard library are are becoming invalid if new items are added.
Actually, this isn't true for std::list. Inserting elements into an std::list never invalidates any iterators in the list (including the end() iterator).
It also isn't necessarily true for other containers, but the details depend on the container. However, for many of the standard containers, there are only limited cases where iterators remain valid after inserting an element.
Best regards,
John
-
February 22nd, 2008, 08:27 AM
#6
Re: An intelligent iterator for std::list
Just for fun: A little modification of your code:
Code:
typedef std::list<int> intList;
typedef intList::iterator myListIter;
intList myList;
myListIter iter = myList.end();
while (1)
{
if (iter == myList.begin())
{
myList.push_back(2);
myList.push_back(4);
myList.push_back(6);
}
}
Works as you would expect.
Thanks, jwbarton. I stand corrected.
More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity. --W.A.Wulf
Premature optimization is the root of all evil --Donald E. Knuth
Please read Information on posting before posting, especially the info on using [code] tags.
-
February 22nd, 2008, 08:51 AM
#7
Re: An intelligent iterator for std::list
Thanks Treuss and John but this doesn't really get me any nearer to a solution. In my original example, the iterator apparently IS getting modified each time I add an element (in fact, I suspect that adding a new element resets the iterator - either to end() or to the newly added element).
[Edit...] Actually Treuss, I re-read your post and I suspect you might be right. A null end pointer will still be a null end pointer, even after adding new elements. This would also explain why your modified example worked but my original example didn't..!
Interestingly, for this code:-
Code:
if (iter == myList.end())
iter++;
if (iter == myList.end())
{
CallSomeFunc();
}
'CallSomeFunc()' would actually get called - indicating that if the iterator is NULL, it doesn't get incremented any further.
Last edited by John E; February 22nd, 2008 at 08:58 AM.
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
February 22nd, 2008, 08:56 AM
#8
Re: An intelligent iterator for std::list
In your original example, the iterator is set to begin() on an empty list, which is the same as end(). When you insert elements into the list, it still maintains the value of end() (it doesn't change, and is still the valid value of the end() iterator).
No insert operation on a list is going to change the value of a separate variable. You have to provide this logic yourself. The standard library doesn't provide any iterators which have this kind of functionality.
Best regards,
John
-
February 22nd, 2008, 08:59 AM
#9
Re: An intelligent iterator for std::list
Sorry John - I re-edited my post while you were typing. Does that explain why my second example also works?
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
February 22nd, 2008, 09:08 AM
#10
Re: An intelligent iterator for std::list
 Originally Posted by John E
'CallSomeFunc()' would actually get called - indicating that if the iterator is NULL, it doesn't get incremented any further.
Incremeanting an end pointer is, I believe, once again undefined behaviour. I would have to check the details, but I believe that it could even crash, as incremeanting a list iterator usually requires dereferencing. Not sure though and don't have the standard at hand...
More computing sins are committed in the name of efficiency (without necessarily achieving it) than for any other single reason - including blind stupidity. --W.A.Wulf
Premature optimization is the root of all evil --Donald E. Knuth
Please read Information on posting before posting, especially the info on using [code] tags.
-
February 22nd, 2008, 12:44 PM
#11
Re: An intelligent iterator for std::list
It isn't valid to increment an iterator which has the end() value (as treuss said - undefined behavior).
My compiler (Visual C++ 2008) gives diagnostic messages in debug mode when attempting this.
Running it in debug mode with iterator debugging turned on (the default mode), I get a diagnostic:
Expression: list iterator not incrementable
If I turn off iterator debugging, I still get an assert in debug mode on the increment of the iterator.
You also shouldn't think of the end iterator as a NULL value. It is a special value indicating the end of the list. Since an iterator isn't a pointer, this value isn't NULL. It might be implemented as NULL internally on some compilers, but this is not something to rely upon.
Best regards,
John
-
February 22nd, 2008, 04:16 PM
#12
Re: An intelligent iterator for std::list
 Originally Posted by treuss
Incremeanting an end pointer is, I believe, once again undefined behaviour. I would have to check the details, but I believe that it could even crash, as incremeanting a list iterator usually requires dereferencing. Not sure though and don't have the standard at hand...
Did a quick scan but couldn't find anything relevant. Don't know for sure, but I recall that dereferencing end() is UB. And as you rightly mentioned that you cannot go to ++end() for a list iterator without dereferencing end(), it is UB as well.
Can you help me with my homework assignment?, Before you post!, Use code tags, How to post!, Codeguru technical FAQs, C++ FAQ Lite, Stroustrup: C++ Style and Technique FAQ, Guru of the Week, Comeau C and C++ FAQs, Comeau C++ Templates FAQs, CUJ @ DDJ, Spam threshold
My Blogs : Learning C++ is fun | Abnegator's reflections
Open Threads : C++ Aha! Moments | Nature of work in C++?
-
February 22nd, 2008, 04:25 PM
#13
Re: An intelligent iterator for std::list
 Originally Posted by John E
But surely myList.end() should be returning the modified end point - not the original end point.
Something's wrong here - either myList.end() is returning the wrong element or i ter is somehow getting updated as elements get added.
What I need is an iterator that remembers where it was - even if new elements get added (which doesn't seem to be what's happening).
What should it remember? When you do something like this:
Code:
std::list<int>::iterator it = myList.begin();
and then later add up stuff into the list, how does the variable it know what it was initialized with? begin() or end() or may be some other already existing element? And once a value is inserted or let's say the element pointed to by it is removed where should "it" now point to? One ahead or one behind? It is just too much documentation to have some behaviour of that kind and probably would be inefficient too!
.end() call will always give you one past the last element. That is by definition. That is not the culprit here. The culprit is "iter" object. As a boundary condition, when the list is empty begin() == end() but that is just a special case for the boundary condition since there is no element for begin() to point to and there is no element for end() to point beyond of!
.begin() will always return the beginning element of the sequence (except for when empty). If you want your iterators to move on inserts and push backs, you will need to do that manually or take use of return value of insert (overload taking position). If you are doing push_back then to get iterator to this push_backed element, you can do --myList.end(). That is, you will need to code to handle to iterator movements.
What is it that you are trying to achieve?
Can you help me with my homework assignment?, Before you post!, Use code tags, How to post!, Codeguru technical FAQs, C++ FAQ Lite, Stroustrup: C++ Style and Technique FAQ, Guru of the Week, Comeau C and C++ FAQs, Comeau C++ Templates FAQs, CUJ @ DDJ, Spam threshold
My Blogs : Learning C++ is fun | Abnegator's reflections
Open Threads : C++ Aha! Moments | Nature of work in C++?
-
February 23rd, 2008, 02:39 AM
#14
Re: An intelligent iterator for std::list
 Originally Posted by exterminator
What is it that you are trying to achieve?
Basically, I'm iterating through a long list and (as I go along) I might want to add new elements to the list. The new elements will always be added using either push_back() or insert() - but either way, they'll always be inserted at a later position than the current iterator pos. I just want to be sure that this won't upset the iterator because (ideally) I don't want to have to keep resetting it back to the beginning after each new addition.
My understanding of std::list is patchy but according to MSDN, end() returns:-
a bidirectional iterator that addresses the location succeeding the last element in a list. If the list is empty, then list::end == list::begin.
This is why I was surprised that, after adding elements to an empty list, list::end() was apparently still returning list::begin()
(or, to put it another way, it was still returning the same thing it returned when the list was empty).
"A problem well stated is a problem half solved.” - Charles F. Kettering
-
February 23rd, 2008, 03:26 AM
#15
Re: An intelligent iterator for std::list
 Originally Posted by John E
This is why I was surprised that, after adding elements to an empty list, list::end() was apparently still returning list::begin()
(or, to put it another way, it was still returning the same thing it returned when the list was empty).
No! begin() will always return the first element and end() will always return one past the last element (that could be anything from a NULL pointer to any custom node having some identification of not being part of the list).
The problem is with empty lists - the boundary condition - then begin() and end() need to return true on equality comparison. But this will not happen in any other scenario.
The problem you are facing is because you cached the begin iterator and due to the specific implementation's way of representing begin() and end() when empty, you get that begin() initialized iterator to be always same as what end() returns. Do not cache that value and you should be okay. Your iterators you fetch from begin (which you get for a non-empty list) will always remain intact if you don't push an element at the beginning. Even then that just changes the definition of that iterator. That is no longer a begin() iterator since something got inserted before it but you can use the iterator or a reference to that element without any issues. You can do op-- to reach to the newly inserted element at the head (you can do op-- and op++ to list iterators shows that the iterator is bidirectional).
All iterators would remain valid as long as they are not removed. But again, note the boundary condition as above.
If this doesn't help, can you show some code as to what you are doing and what you want that code to do exactly?
Can you help me with my homework assignment?, Before you post!, Use code tags, How to post!, Codeguru technical FAQs, C++ FAQ Lite, Stroustrup: C++ Style and Technique FAQ, Guru of the Week, Comeau C and C++ FAQs, Comeau C++ Templates FAQs, CUJ @ DDJ, Spam threshold
My Blogs : Learning C++ is fun | Abnegator's reflections
Open Threads : C++ Aha! Moments | Nature of work in C++?
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|