STL Iterator Assignment When List is Empty?

Started by
8 comments, last by Stoffel 19 years, 7 months ago
Is there anything wrong with assigning an iterator to a container before any items have been inserted into that container? Like this:


list<int> ilist;
list<int>::iterator ilist_it = ilist.begin();

ilist.push_back(1);
ilist.push_back(2);

cout << *ilist_it << '\n';


Also, it is ok to fill a list (just) by using push_back's, right? There won't be any problem with inserting at the "back" of a zero element list? Thank you. --Cam
Advertisement
There's no problem with calling push_back on an empty list.

As to your other question about getting 'begin' before pushing anything onto the list, I suspect that it's implementation specific and undefined. I know that in the implementation I use begin on an empty list will return you a NULL pointer. But.... why don't you just write a test case and find out?
yes, i beleive that on the push_back calls, the .begin()
pointer becomes invalid, its the same as iterating through
a container and incorrectly deleting items.

put the assignment AFTER the push_back's
"I am a donut! Ask not how many tris/batch, but rather how many batches/frame!" -- Matthias Wloka & Richard Huddy, (GDC, DirectX 9 Performance)

http://www.silvermace.com/ -- My personal website
There is nothing wrong with calling begin() on an empty container. In that case begin() == end().

However, after the push_back(), the value returned by begin() may (and probably will) change.
John BoltonLocomotive Games (THQ)Current Project: Destroy All Humans (Wii). IN STORES NOW!
Quote:Original post by hereticam
Also, it is ok to fill a list (just) by using push_back's, right? There won't be any problem with inserting at the "back" of a zero element list?

Thank you.
--Cam


It will functionally work so there's nothing incorrect about it, but it can be inefficient if you don't use vector::reserve first. Otherwise, your vector will have to reallocate, copy itself, and delete the old memory as it grows one element at a time*.

Even if you don't know how large it will be, if you insert blocks at a time, it's best to reserve for that additional block size ahead of the push-back calls. For example, if you knew you always inserted 8 elements at a time, but you aren't sure how many times you're going to do that, just have a call to v.reserve (v.size () + 8) at the top of the function, then push_back 8 times.

*Some implementations grow by 1.5x or 2x size each time they need to reallocate, so it's not like it's reallocating every single element.
The iterator validity rules are written without regard for the number of elements in the list.

If the iterator validity rules for a container say that iterators are not invalidated by an operation, then that holds true even of the first insertion.

However, because the beginning has "moved", the iterator you retrieved from begin() will still point at the end of the list even after the insertion. So dereferencing it will be invalid.
char a[99999],*p=a;int main(int c,char**V){char*v=c>0?1[V]:(char*)V;if(c>=0)for(;*v&&93!=*v;){62==*v&&++p||60==*v&&--p||43==*v&&++*p||45==*v&&--*p||44==*v&&(*p=getchar())||46==*v&&putchar(*p)||91==*v&&(*p&&main(0,(char**)(--v+2))||(v=(char*)main(-1,(char**)++v)-1));++v;}else for(c=1;c;c+=(91==*v)-(93==*v),++v);return(int)v;}  /*** drpizza@battleaxe.net ***/
Quote:Original post by Stoffel
Quote:Original post by hereticam
Also, it is ok to fill a list (just) by using push_back's, right? There won't be any problem with inserting at the "back" of a zero element list?

Thank you.
--Cam


It will functionally work so there's nothing incorrect about it, but it can be inefficient if you don't use vector::reserve first. Otherwise, your vector will have to reallocate, copy itself, and delete the old memory as it grows one element at a time*.


Er, this is true, of course, but the OP is using a list, not a vector. Lists, of course, do not have this problem since they do not require their memory to be sequential.

As a general comment to other posts, note that the only operation that will ever invalidate a list operator is erasing the element it points to - inserting elements and erasing elements other than the one an iterator is pointing to will not invalidate it.
Quote:Original post by Miserable As a general comment to other posts, note that the only operation that will ever invalidate a list operator is erasing the element it points to - inserting elements and erasing elements other than the one an iterator is pointing to will not invalidate it.


i beleive that is actually incorrect, you would think that
the std::list.begin() wouldn't be invalidated by a push_back? (I certainly didn't beleive it!)

but... actions speak louder that words:
#include <list>#include <iostream>using namespace std;int main(){list<int> a;list<int>::iterator b = a.begin();a.push_back( 200 );a.push_back( 300 );a.push_back( 400 );cout << *b << endl << flush;}


out puts a random garbage integer value, where as if the
iterator is set AFTER the push_back calls, it outputs '200'
as expected. if you try this with a std::vector it crashes.

there is still a smaaall chance that it could just be cout
(somehow cout gets a garbage address?)

[NOTE: G++ 3.2 "-W -Wall list_test.cxx -o test"]
"I am a donut! Ask not how many tris/batch, but rather how many batches/frame!" -- Matthias Wloka & Richard Huddy, (GDC, DirectX 9 Performance)

http://www.silvermace.com/ -- My personal website
Quote:Original post by silvermace
Quote:Original post by Miserable As a general comment to other posts, note that the only operation that will ever invalidate a list operator is erasing the element it points to - inserting elements and erasing elements other than the one an iterator is pointing to will not invalidate it.


i beleive that is actually incorrect, you would think that
the std::list.begin() wouldn't be invalidated by a push_back? (I certainly didn't beleive it!)

but... actions speak louder that words:
*** Source Snippet Removed ***

out puts a random garbage integer value, where as if the
iterator is set AFTER the push_back calls, it outputs '200'
as expected. if you try this with a std::vector it crashes.

there is still a smaaall chance that it could just be cout
(somehow cout gets a garbage address?)

[NOTE: G++ 3.2 "-W -Wall list_test.cxx -o test"]

No, std::list.begin() will not be invalidated by a push_back(). In a zero-element list, it is of course the case that begin() will be equivalent to end() and so point to no valid element, and obviously will not be the same as another call to begin() after a push_back(), but it's still a valid (end) iterator.

And yes, of course it outputs garbage in your initial scenario; you're printing *end(). Just because you insert an element, this does not mean that the iterator returned by begin() suddenly points to an existing element.
Quote:Original post by Miserable
Er, this is true, of course, but the OP is using a list, not a vector. Lists, of course, do not have this problem since they do not require their memory to be sequential.

Whoa, that's the last time I post on the weekend while watching poker tournaments.

This topic is closed to new replies.

Advertisement