Hello, I'm currently trying to figure out how to store the copy of an object in a std::list so the data of the list entry remains untouched when the object I was getting the data from is getting destroyed.
Now I know I can simply add an entry in a std::list with push_front()/push_back() but I can't seem to find any clear statement if the object that gets added to the list is a copy or just a pointer of/to the original object.
I already tried to test some stuff with sample code but I'm not sure what to make out of it. Maybe someone can explain to me what is happening in the following sample code:
1 2 3 4 5 6 7 8 9 10 11 12 13
std::list<Object*> pointer_list;
std::list<Object> object_list;
Object* test = new Object(/*the constructor gets called with some parameters here*/);
// here some funtions of test are called and its data members are being modified
pointer_list.push_back(test);
object_list.push_back(*test);
delete test;
// after this line is called, the data members of test are being "deleted" as well as the data in the according list entry in pointer_list
// however in object_list the entry seems to remain untouched, does that mean the object was actually being copied in it?
Since the data in object_list was not "deleted" I dare to ask: Is this the way to do what I wanted to do? Or is there some other, "proper" way to do this?
It is a copy. The copy constructor is called. To do it how you want to, you should not delete the pointer and keep reference of how many time it is used (Reference counting).
Well in practice I don't delete the pointer manually, I just want to be sure that the data stays untouched in the list after it was being put in it.
Would it be best to use a smart pointer for the reference counting?
Also does the above code produce any memory leaks in that matter or was the data being copied in a clean way into the list until it gets properly deleted out of the list with erase()/clean()/pop_front()/pop_back?
Or to put it in another way - is the above code also usable for me or should I avoid coding like this? :P
It's not so simple to use a smart pointer for reference counting.
and no, it doesn't get a memory leak, but the pointer in pointer_list is nomore valid.
Your idea should be like using only one of the twos:
1 2
std::list<Object*> ptrlist;
ptrlist.push_back(new Object( /*...*/ )); // No copy constructor of Object called, the faster way
In case you use the first example i showed you up ( std::list<Object*> ptrlist; ) When you delete the std::list you should delete all the internal pointers. Or you can use a smart pointer but you will not be using reference counting ( std::list< std::auto_ptr< Object > > ptrlist; )
{
std::list<Object*> ptrlist;
ptrlist.push_back(new Object());
} // <- ptrlist destructor called, let's follow:
/*
1. ptrlist.~std::list<Object*>();
2. ptrlist[0].~(Object*)();
Here, the destructor is the (Object*) destructor,
Not the Object destructor itself! This results in a memory leak!
If before ptrlist was destroyed you did:
delete ptrlist[0]; (Or whatever it was)
That was going to result to call
ptrlist[0]->~(Object)();
Notice also the difference over from a '.~' and '->~'.
*/
So doing it like this would be fine (no memory leaks)?
1 2 3 4 5 6 7 8
std::list<Object*> ptrlist;
ptrlist.push_back(new Object());
Object* PointerToObject = ptrlist.back(); //I use the pointer here because it makes things easier for me in my code (less text)
/*doing some stuff here*/
delete PointerToObject;
ptrlist.pop_back();
edit: sadly I can't call the list entries by index but I can iterate through it so that should be fine too
EssGeEich is correct in that you should use a smart pointer so you do not have to manually delete these objects.
However you should not use auto_ptr because it's deprecated (and it doesn't even work when used in standard containers). Replace it with unique_ptr or shared_ptr.