Re: std::list of class pointers, understanding problem (with minimal
example)
On Jul 28, 1:00 pm, Frank Steinmetzger <War...@gmx.de> wrote:
Hello group
I am trying to solve a segfault in a project of mine. To better understan=
d
what's going on, I wrote a minimal program to see how deletion of list
elements behaves if the list stores only pointers to class instances.
Looking at the STL source confirmed what I suspected - the instance is no=
t
deleted when erasing the list item and its pointer, so I did not find the
solution to my primary problem yet.
But I found something else in the program that I am curious about. It:
- defines a class k with a private member and an accessor get()
- uses std::list<k*> to store some instances of k
- has an output function that iterates through a list and outputs the
value of the class pointer and the result of pointer->get()
- declares two lists and fills them with three identical class instances
- deletes the middle item in list 1 and destroys its instance of k
List 2 has now, to my understanding, an invalid pointer in item 2, so it
should segfault when calling the output function, should it not?
But instead, the output function prints out "0". Where am I wrong here?
Thanks in advance for your time.
Here's the program (EDIT: I know it doesn't clean up at the end, but =
I
omitted it for a smaller posting :-))
#include <iostream>
#include <list>
using namespace std;
class k {
private:
int i;
public:
k(int _i) {i=_i;};
int get() {return i;}
~k() {cout << "destroyed #" << i << endl;}
};
void output(list<k*> &l) {
for (list<k*>::iterator i=l.begin(); i!=l.end(); i++)
cout << (*i) << ": " << (*i)->get() << endl;
cout << endl;
}
int main (int argc, char* argv[]) {
list<k*> list1,list2;
k* pk;
for (int i=1; i<4; i++) {
pk=new k(i);
list1.push_back(pk);
list2.push_back(pk);
}
output(list1); output(list2);
list<k*>::iterator it=list1.begin();
it++;
delete(*it);
list1.erase(it);
output(list1); output(list2);
return 0;
}
You store pointers to same objects in two lists. Then you remove one
pointer from one list and you delete object this pointer points to.
The other list still contains the same pointer, but that pointer
points to... well, undefined behavior, as said. This is the source of
your problem.
You must understand this first: in C and C++ (and some other
languages, but the root cause of your trouble here is C), you manage
heap manually. You must know where your pointers point to and where
they are, at any point in time. You must, if you delete object pointed
to some pointer, never again try to access said object (there is no
object anymore). That means, if you have several pointers to one
object, and you delete said object, you must do something with all
these pointers (e.g. track them down and set them all to NULL).
In your example, you could do:
list<k*>::iterator it=list1.begin();
it++;
delete(*it);
list1.erase(it);
// Remove^^^ pointer from list 2
it=list2.begin();
it++;
list2.erase(it);
^^^ but NOT delete, as deleting twice is undefined behavior.
Alternatively, you could use list<shared_ptr<k> > (NOT
list<shared_ptr<k*> > as suggested by Martijn). This is because
shared_ptr (of boost, or upcoming C++0x library) handles object
lifetime for you using a technique called "reference counting".
Goran.