Advertisement

Confusion on vector of pointers

Started by January 18, 2002 04:02 PM
8 comments, last by laotzu 22 years, 10 months ago
When you have a vector of pointers to a class that were allocated using 'new', and then you wish to erase one of those elements - do you still have to call delete somewhere? I understood it that when erasing elements from a vector, the destructor is called once for each element. So would we put the delete in the destructor... is that even possible? Ack, I'm confused - I reckon maybe I should just take a break for awhile. Thanks for the help, -lao P.s., this is how I have it now... vector< CPlayer* > players; ... vector< CPlayer* >::iterator i; for(;; ) { for(i = players.begin(); i != players.end(); i++) { if(!(*i)->bTakeTurn()) { players.erase(i); } } } Edited by - laotzu on January 18, 2002 5:04:40 PM
quote: From MSDN (because SGI doesn''t document individual methods):
Erasing N elements causes N destructor calls and an assignment for each of the elements between the insertion point and the end of the sequence. No reallocation occurs, so iterators and references become invalid only from the first element erased through the end of the sequence.

So, no, you do NOT need to call any destructors.

[ GDNet Start Here | GDNet FAQ | MS RTFM | STL | Google ]
Thanks to Kylotan for the idea!
Advertisement
He will still need to delete his objects somewhere, since pointers have no destructors. Otherwise, that''s a nice memory leak.

So yes, when you erase an object, you''ll need to call delete on the pointer. However, as Oluseyi said, the iterators will be invalidated, so save the pointer(s) in temporary storage before calling erase, then call delete and discard the temporary.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
I thougth the same. But if you try it you will see he is rigth;

  vector <p*> vec;p* t = new p();vec.push_back (t);vec.erase (vec.begin ());t.mVar//here you will see an exception because the object was deleted  
humanity will always be slaved by its ignorance
quote: Original post by hewhay
I thougth the same. But if you try it you will see he is rigth;


t.mVar//here you will see an exception because the object was
[/source]


Actually you''re a dumbass, and wrong.

here''s my output:
Constructor
hi
  class blah{ public:	blah() { cerr<<"Constructor"<<endl; }	void hi() { cerr<<"hi"<<endl; }	~blah() { cerr<<"Destructor"<<endl; }};int main(){	vector<blah*> p;	blah* t = new blah();	p.push_back(t);	p.clear();	t->hi();	return 0;}  
quote:
Actually you''re a dumbass, and wrong.

Thank for insight, you allmigthy and allknowing being.
jerk.

Now can somebody explain me were the exception is generated here
  class blah{ public:    blah() { cerr<<"Constructor"<<endl; }    void hi() { cerr<<"hi"<<endl; }    ~blah() { cerr<<"Destructor"<<endl; }};int main(){    vector<blah*> p;    blah* t = new blah();    p.push_back(t);    for (vector<blah*>::iterator it = p.begin();it != p.end();++it) // tried with it++ also	p.erase (it);     cout << "end";    t->hi();    return 0;}  
humanity will always be slaved by its ignorance
Advertisement
When you do erase, one element is removed from the vector. Which means that end() moves one step towards begin(). Since there was only one element, end() == begin(). Then at the end of the loop, you increase your iterator, which was also equal to begin(). Which makes it go past the end. Since you are testing for inequality and not doing a comparison (which you can since vectors have random access iterators), your for loop happily goes past the end and starts to erase stuff which doesn''t exist.

Paf ! Exception.
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
quote: Original post by hewhay
Now can somebody explain me were the exception is generated here.

The exception occurs on the second iteration of the loop when the comparison it != p.end() should fail. I found that assigning p.end() to a temporary variable solved the problem, but I''m still trying to reason out why.

[ GDNet Start Here | GDNet FAQ | MS RTFM | STL | Google ]
Thanks to Kylotan for the idea!
quote: Original post by Oluseyi
The exception occurs on the second iteration of the loop when the comparison it != p.end() should fail. I found that assigning p.end() to a temporary variable solved the problem, but I''m still trying to reason out why.


If you save end() to a temporary, it doesn''t get bumped when you call erase. Then increasing ''it'' makes it point to the old position of end() and the test succeeds.

It gets tricky when you do several erase in a row, since testing against the original end() may still let you go into undefinedland (also known by some as segfaultland).
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." — Brian W. Kernighan
quote: Original post by Fruny
If you save end() to a temporary, it doesn''t get bumped when you call erase. Then increasing ''it'' makes it point to the old position of end() and the test succeeds.

It gets tricky when you do several erase in a row, since testing against the original end() may still let you go into undefinedland (also known by some as segfaultland).

This is why there''s an erase(start, stop) form, because all iterators following the end of the deleted sequence are invalidated.

[ GDNet Start Here | GDNet FAQ | MS RTFM | STL | Google ]
Thanks to Kylotan for the idea!

This topic is closed to new replies.

Advertisement