How could I free up a linked list that contains dynamically allocated objects?
I try to use list<class*> lists, but then I could not use the insert() function to insert object to the list. Does anyone know what is the cause?
std::list<boost::shared_ptr<YourType> > will automatically call YourType::~YourType on each (smart) pointer in the list, when the list is deleted. And if you erase one list element, it will call YourType::~YourType for that one element. You can still call list.insert(new YourType)
Link: www.boost.org
how could I free up linked list that contain dynamically allocated object?
Walk the list, deleting the contained object for each link, or better in some cases, write a link dtor that deletes the contained object.
I try to use list lists, but then I could not use insert()function to insert object to the list. Does anyone know what is the cause?
Not without seeing your code.
Traverse the list from the beginning to end, and delete one by one.
The solution used by the STL is to have the container own the objects it contains. In this scenario each node would be responsible for deallocating it's object when it's destructor is called. You're still responsible for deallocating the copy of the object you pass in.
Edit
If you're attempting to use the stl List and encountering an error, it might be the case that the object you're trying to place inside does not implement a copy constructor. This can happen if you try to stick things other than pointers into the list. If you're comfortable with pointers you might consider storing them in your containers instead of the objects themselves. This will require that you call 'delete' yourself on the pointer when you're done with it. This is typically done by calling 'delete' on the pointer contained in a node when you remove it or by walking the list when you're done with it and calling 'delete' on the contents of each node.
You will have to iterate the list and delete the dynamically allocated objects, before clearing the list.
When using containers of newed
pointers, please remember to delete
the pointers before the container is
destroyed.
About problem using insert() : I am not very sure what is the problem you are facing. From the explanation, I assume, you are trying to insert objects of Class into list where as the list contains the pointer to Class. Could you please elaborate the problem with insert?
Pseudo code for deleting the dynamically allocated objects:
version 1: Simple
list<Class*>::const_iterator iter = m_ClassList.begin();
list<Class*>::const_iterator endIter = m_ClassList.end();
for(;iter!= endIter ; ++iter)
{
delete *iter;
}
ClassList.clear();
version 2: A better version using for_each
struct DeleteClassObject
{
//Functor
template<typename T>
void operator()(const T* ptr) const
{
delete ptr;
}
}
//loops through list and deletes the dynamically allocated objects using
//functor DeleteClassObject
for_each( m_ClassList.begin(), m_ClassList.end(), DeleteClassObject ());
DeleteClassObject.clear()
You could use ptr_list from Boost
http://www.boost.org/doc/libs/1_38_0/libs/ptr_container/doc/ptr_list.html
EDIT: THIS IS WRONG, SORRY
If you're using std::list then there's a clear function to delete all objects you put in.
std::list test;
test.clear();
Oh, and .clear() also invokes the destructors.
To use the insert function of such lists you need to specify the position via an iterator.
test.insert(test.end(), 5);
But there's more than 1 insert function, here you can find more details
EDIT
Could somebody leave a comment when downvoting?
Start your project in language/environment, which having an automatic memory management (Garbage collection). Then things like that will be the least which you care about. It will save your time to put your efforts into something else.
Related
I am currently coding a shell in c++ whose file-system is implemented in main memory. I am trying to store the pointers to inodes which is either plain field or directory in a ordered map in the following manner:
using inode_ptr = shared_ptr<inode>;
map<string,inode_ptr> dirents;
So basically the string will map either a file or a directory. For the rm "remove function", what I am trying to do is to deallocate what the pointer points to and the pointer itself by using delete:
void directory::remove (const string& filename) {
DEBUGF ('i', filename);
delete dirents[filename];
dirents.erase(filename);
}
So basically, I deallocate the object and the pointer, and then delete it from the map; however, I am getting a compiler error which states the following:
error: type ‘std::map<std::basic_string<char>, std::shared_ptr<inode> >::mapped_type {aka class std::shared_ptr<inode>}’ argument given to ‘delete’, expected pointer
delete dirents[filename];
what am I doing wrong?
I also think that somehow the idea is wrong because the deletion of a directory has to be recursive. Eliminating what the ptr points to doesn't get rid of the whole chain; however, I don't know if that's true.
Your problem lies in the try of deleting a std::shared_ptr<T>. You do not perfom a delete on that object. The destructor of it does what you really want for you. Simply call erase on your map at specified key and, while you erase that object, the destructor will automatically delete the content if there are no remaining shared_ptrs referencing this allocation (very good point user4581301 ).*
Your function would look like that:
void directory::remove (const string& filename) {
DEBUGF ('i', filename);
dirents.erase(filename); // erasing that object makes it call a delete on content
}
EDIT: Just some quick tip - if your map provides the only way of accessing those pointers, consider using std::unique_ptr<T> instead of std::shared_ptr<T>.
*if you really want to perform a delete there, I would highly encourage you to switch to unique pointers. Usage of shared ones indicates that there might be some other pointers pointing to the memory you want to deallocate. If that's the case - your original approach was not correct. Either use std::unique_ptr here or don't assume you could delete the content of the ptrs.
It's my first time posting so I do apologize if I've messed up in anyway or made anything more difficult than it should be.
Here's my issue:
I'm trying to erase data from a vector of boost::shared_ptr nodes, nodes being a class.
In one part of my code, erasing an element from a vector known as openList works fine.
In another part of my code, erasing an element from a vector known as movingObjectsList, doesn't want to work. It gives prompts me with _block_type_is_valid(phead- nblockuse).
I've tried clear(), popback() and erase() and all of them cause the same problem. I can add what I like to movingObjectsList without any errors and swap the data it holds with other vectors, but I'm unable to delete any of the data.
I think I've ruled out it being an issue with the node destructor because I have the same issue when I use Ints instead of nodes, and also the openList is able to erase elements.
This is how it's declared in the header.
vector<boost::shared_ptr <node>> movingObjectsList;
This is the relevant code in the cpp
grid::grid()
{
movingObjectsList = vector<boost::shared_ptr<node>>();
}
void grid::createGrid(){
boost::shared_ptr<node> movingObject = boost::shared_ptr<node> (&nodes[8][8]);
movingObjectsList.push_back(movingObject);
}
void grid::movingObjects()
{
movingObjectsList.erase(movingObjectsList.begin());
}
This is the simplest form I've cut it down to, only concerning movingObjectsList.
Without the erase function, it works fine.
As answer I reiterate what I said in my comment: When the reference counter of a shared_ptr reaches zero the contained pointer will be deleted. This means that it will basically be the same as delete &nodes[8][8]. As it's not allocated with new, you will experience undefined behavior.
OK, mistake in what a shared pointer does.
A Shared pointer takes full ownership of a pointer. When that pointer goes out of scope, it'll delete that pointer.
You are inializsing the nodes as an node [8][]. Your pointer is an address in this 2D array! When you need to call delete (which'll get called when your shared_ptr goes out of scope i.e. whenever you remove elements from the vector), you are essentially calling delete nodes[i][j], which you'd expect to barf.
Just use references in this case (Node&), which will be perfectly valid and work just fine.
So I have some C++ classes that use a map and key class for a sort of data structure. In my insert method I use the typical map.insert. I want this function to return a pointer so I can modify some values (not the one used for comparison) inside the element inserted. So I was wondering if this is safe to this..
template<typename T>
NodeT<T> * TreeT<T>::
MakeNode(PointT point)
{
NodeT<T> * prNode = new NodeT<T>;
//set the contents for the node
prNode->SetNode(point, m_dTolerance);
//Create the key class using the
VectorKey key(point, m_dTolerance);
//Store the key,node as a pair for easy access
return_val = m_tree.insert( pair<VectorKey, NodeT<T> >(key, *prNode) );
if (return_val.second == false)
//if return_val.second is false it wasnt inserted
prNode = NULL;
else
//it was inserted, get a pointer to node
prNode = &(return_val.first->second); //is this safe if I plan to use it later?
return prNode;
}
I seemed to learn the hard way that my original pointer (the one I created with new), was pointing to the wrong element after the insert. Can anyone tell me why that is? So I used the return_val iterator to get the right pointer. I kinda dont want to return an iterator but if its safer then I do...
Thanks!
You seems to have troubles in your code with pointers and values. First you allocate an object on a heap ( with new Node )
Then you use a copy of that object to sore within your map.
PS. And then you loose original object forever as do not free memory which leads to memory leak.
In your case - it is invalid because you return pointer to object which can be deleted at any time ( for example next time you add something to your map and map decides to reallocate it's tree, so it will copy objects to different places ).
Storing pointers as map values prevents this. The only thing you need to remember to clear them up when removing object from map and when removing map itself.
The easy way to handle that would be using smart pointers (boost::shared_ptr for example ) or smart map class (boost::ptr_map for example ).
To fix that - use pointers everywhere ( store a pointer as a map value ).
This way - you will be able to return pointer from this function and it will be valid.
So just turn your map to map*> and this should fix most of your problems.
Do not forger to delete objects when erasing them from the map.
This code sample is interesting because contains a several things wrongs or to avoid.
Implementation
The most important things are been said (mainly by Bogolt):
You are leaking memory, because allocate NodeT<T> from the heap and never free it again, since map will allocate a copy of the object, not the pointer. Indeed, you specify as parameter *prNode, not prNode.
You use the heap to allocate the object (will be copied into the map), but you assume you always allocate the object. Despite it will be the very most probably case, that is not alway true: new operator would be return null or throw a bad_alloc exception. The code does not handle it.
Anyway, you use the heap when is not really needed. (And you see the problems are you intriducing because that). You can just create the object in the stack and then insert into the map, avoiding the previous problems and typing less code.
Design
The function returns a pointer to the element in the map. Depending the program, is possible this is safe. But what happens if the code reference the pointer when the object is removed from the map? Better, if you are returning pointer, do not return a raw pointer. Use smart pointer (shared_ptr in this case) instead. Using shared_ptr you will have not problems with the object life.
Other reason to use smart pointers: because the insertion into the map imply a copy of the element, you are imposing a requirement to NodeT<T>: it has to be copy constructible. May be this requirement is not important for performance, but may be in other circumstances copying the object have drawbacks. If you use smart pointer (or boost::ptr_map), the object will be created just once and is not copied.
Style
Just some suggestion, but not too important:
instead type pair<VectorKey, NodeT<T> >(key, *prNode), type make_pair(key, *prNode). The code is more compact and clearer typing less.
Well I'd say that depends on is your map alive longer than anything that could use (and store) the pointer.
If yes, (ie, it's in some sort of singleton), you could go with it, but not very safe anyway since any code could delete the pointer.
The best option is to store boost::shared_ptr (or std:: since c++11) instead of raw pointers in your mapn and return only a weak_ptr after insertion.
That way, you're sure no other code can delete your pointer as long as the map holds it, and that no one can use a pointer that has been erased from the map.
I have a an object that will potentially end up in multiple lists.
For example
std::list<object*> lista = new std::list<object*>();
std::list<object*> listb = new std::list<object*>();
object* obj = new object();
lista->push_front(obj);
listb->push_front(obj);
Potentially, there are many objects that will end up in both lists in the same way. I realize smart pointers would be the easy thing to do, but call me a masochist - I'd prefer to figure out how to do it without.
Currently, I'm trying this technique:
td::list<object*>::iterator iter;
for(iter = lista->begin(); iter != lista->end(); iter++) {
delete (*iter);
*iter = 0;
}
std::list<object*>::iterator iterB;
for(iterB = listb->begin(); iterB != listb->end(); iterB++) {
if(*iterB != 0) {
delete (*iterB);
*iter = 0;
}
}
delete lista;
delete listb;
But it breaks on my equivalent of delete lista; at run time. Hopefully someone out there smarter about pointers can help me out. Thanks in advance!
P.S. I'm running Windows 7/MinGW.
A main problem is that you (apparently, you do not offer complete code) delete an object twice: once when iterating through list A, and once when iterating through list B.
There are three main solutions:
Use a ref-counting smart pointer like std::shared_ptr.
Recommended. Your statement that you do not want to use a smart pointer seems to be made out of ignorance rather than some silly-manager's requirement.
Keep the nodes also in a primary list:
delete a node only when you know that the only list it's still in, is the primary list.
Implement a reference count yourself:
The easiest is again to use an existing library solution such as boost::intrusive_ptr, but all you have to do is to meticulously maintain a reference count in each node. delete when the reference count goes down to 0.
A fourth possibility is to use a garbage collector such as the Boehm collector, but then the code needs to be structured to support it. Or at least that's my impression. And it may be difficult to get help with that, since very few C++ programmers use that approach (which indicates that it's not entirely free of problems).
Use shared_ptr or have a master list with unique_ptr.
Failing that, have a master list that owns the pointers, and delete from it after you clear but do not delete all other lists.
Failing that, do not directly delete from a list directly. Instead insert the pointers you want gone into a std::set, and either remove them from the other lists before deleting (iterate and find in the set), or accumulate all the pointers you want to dispose of then mass delete them from the set.
This is in rough order of suckitude by paragraph.
Not sure why you don't really want to use shared_ptr. Ok suit yourself. How about you just create a local shared_ptr? If not then load both the list into one master list. Clear the two sublist, and delete each element in the master list as well as clearing the master list.
In the line
if(*iterB != 0) {
*iterB will never be 0. So you are double deleting.
Add counter field to your object. Default initialize to 0. Add +1 on adding to a list. -1 on removal from a list. If counter==0, delete the object.
This is not thread safe as shared_ptr, but it can be much faster for the same reason.
Say I have two classes created work and workItem.
CWorker *work = new CWorker();
CWorkItem *workItem = new CWorkItem();
The work class has a public list m_WorkList and I add the work item to it.
work->m_WorkList.push_back(workItem);
If I just delete work
if(work != NULL)
delete work;
Do I need to loop through the list in the destructor like the following? Any better way to do this? Could I use clear instead?
while(m_WorkList.size())
{
CWorkItem *workItem = m_WorkList.front();
m_WorkList.pop_front();
if(workItem)
delete workItem;
}
Yes you need to delete each item. If you call new N times, then you need to call delete exactly N times as well. There is no shortcut for bulk deleting items.
Also when you're done with it you need to call delete on work.
You can use new[] and delete[] if you want to create an array of items on the heap and release the items on the heap respectively at once. But in your case this isn't what you're looking for.
You can look to boost::shared_ptr if you don't want to manually do these delete calls.
as said in the other responses, you need to loop over your list and delete each elements. if you call clear, it will just remove pointers from the list not pointed objects.
if you need a list with the notion of ownership you can use boost pointer container. it will ensure that your objects are destroyed when you destroy your list
Assuming that you don't maintain a list of workItems elsewhere, then yes, you'll need to delete each of them individually before you delete the Worker itself (thus losing the references). If the Worker holds the only list, then the deconstructor is as good a place as any (otherwise you'll need to delete each workItem "manually" before you call delete on the Worker itself)
However, if the workItems references exist elsewhere, you can choose the appropriate time to delete them, which may or may not be when you delete Worker.
As others have said, you need a delete with every new. The container won't do this for you by default. You don't need to pop the items off the list though. You can create a functor to do the work for you. The following is common practice for people who can't use tr1::shared_ptr or Boost.
struct deleter
{
template <class T>
void operator()(const T* ptr) const
{
delete ptr;
}
};
// Usage
std::for_each(work->m_WorkList.begin(), work->m_WorkList.end(), deleter());
delete work;
It really depends on the ownership, which is what you need to decide on when building the interface. Say you have a method:
CWorker::AddItem(CWorkItem *workItem)
You need to specify who owns the memory, and therefor who should delete it. Depending on what you are trying to do, it could make sense for the caller to own it (like if items should be routinely shared between CWorkers), or for the CWorker to own it (if each CWorkItem belongs to a single CWorker). Whoever owns it is responsible for deleting it.
In the former case, you could take the the WorkItems as shared_ptrs, to specify the ownership is shared between Workers, and you wouldn't need to do manual deletes. In the latter case, you could also use a specialized container like ptr_vector to obviate the need for manual deletes, but you should also but a note on the function that you are taking control of the memory.
Also, as a note, delete is null-safe, so you don't need those if statements, and it would be faster to pop_back() than pop_front()
use boost shared_ptr (which will soon become a standard)
typedef boost::shared_ptr<WorkItem> WorkItemPtr;
....
std::list<WorkItemPtr> list;
...
list.push_back(new WorkItem);
Now when list is deleted the WorkItems will be deleted for you. You can pass WorkItemPtrs around in your code and not have to worry about them.