Sign in to follow this  

STL Iterator Assignment When List is Empty?

This topic is 4859 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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"]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites

This topic is 4859 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this