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.
Related
I'm making the mental transition from old school C++ to "modern".
I have a class factory that is used to make sure all instances of a certain class, foo, are maintained in a list. This list is used to process all foos in order.
This is in a legacy system that uses regular old pointers (new/delete) but I was thinking of turning them into shared_ptrs.
Will I still need a "RemoveMeFromList()" call in the foo's destructor or is there some magic I'm not aware of?
What I propose you in this case is to keep a vector of weak pointers (std::weak_ptr) in your factory:
std::vector<std::weak_ptr<foo>> foo_instances;
Now, with this vector, if one pointer goes out of the scope, it will be expired. So, you can remove the expired pointers next time that you process the vector. In other words, you do not need an explicit "RemoveMeFromList" method, but you can do the removal of expired pointers when you go for processing of the foo instances.
Will I still need a "RemoveMeFromList" call in the foo's destructor
Yes.
or is there some magic I'm not aware of?
No.
You could implement a custom container, that stores weak pointers to objects in shared ownership, and on every access, check whether the pointer is still valid. I don't know if this would be a good design for you (seems dubious).
This is in a legacy system that uses regular old pointers (new/delete) but I was thinking of turning them into shared_ptrs.
You have not really provided us with a lot to go on, but I suspect std::shared_ptr is not what you need. std::shared_ptr is used to "collaboratively manage" ownership by all copies of the pointer, and kill it when there are none. Such killing will not notify your "factory", or central repository, of foos. But since you actually have it, and you want it to keep track of the instances, just let it be the one owning them. At most, you could have the entities which get pointers/references to foo instances instead get wrappers which handle just ref-counting somehow. Your central foo repository will handle deletions - if they are at all necessary. It could recycle unused foos - reinitialize them and hand them out instead of really allocating anything new.
Again, sorry for the rather vague and abstract answer.
You could implement a solution with shared_ptr and weak_ptr as eerorika suggested by doing something like this. You might prefer this solution to unique_ptr if you don't want the Factory to be the owner of the objects which determines when things are invalid.
Your factory class could look something like this:
class Factory {
public:
std::shared_ptr<MyObject> create();
std::vector<std::weak_ptr<MyObject>>& getObjects();
private:
std::vector<std::weak_ptr<MyObject>> objects;
void cullInvalidObjects();
};
We simply create a weak_ptr from the shared_ptr of the object in the factory method:
std::shared_ptr<MyObject> Factory::create()
{
auto object = std::make_shared<MyObject>();
std::weak_ptr<MyObject> weakObject = object;
objects.push_back(weakObject);
return object;
};
The factory can have an internal method that culls objects that are no longer valid:
void Factory::cullInvalidObjects()
{
auto iter = objects.begin();
while (iter != objects.end())
{
if ((*iter).expired())
{
objects.erase(iter++);
}
}
}
and then when getting objects to work on them, you would probably want to cull the list before providing it:
std::vector<std::weak_ptr<MyObject>>& Factory::getObjects()
{
cullInvalidObjects()
return objects;
}
Alternatively, rather than culling you could just get the list and then check for validity in your functions that process it. This is probably not the best solution if you have a large number of invalid items.
void callSomeMethod(std::vector<std::weak_ptr<MyObject>>& objects)
{
for (auto wObj : objects)
{
auto sObj = wObj.lock();
if(p)
{
p->someMethod();
}
}
}
I have this class-object in c++ (using Qt):
class Foo {
public:
Foo();
~Foo();
QList<Bar*> barList;
}
My question is: do I need to delete every Bar object in the barList in the destructor (for loop), or since the list is a static object everything will be deleted with the Foo object ?
Thank you.
You can use qDeleteAll(...) (which is basically a foreach over your list and calling delete on every item inside). Do not use QList::clear() which simply removes the items from the list but doesn't trigger deallocation. You can however combine the two to first release the memory of the objects your list items (pointers) are referencing and then use clear() to remove the items (pointers) themselves from the list leaving you with an empty barList.
In addition to that if Bar is derived from QObject you can just set its parent to another object/widget which you are sure will be properly released at some point. This is the parent-child model in Qt and is a nice way to clean stuff without the need to take care of the deletion yourself.
Also static here is incorrect. I think you mean on the stack that is your barList is not dynamically allocated.
A word of caution: even though you have Bar* this does not mean that the items themselves are dynamically allocated. You can have items created on the stack and then append them by reference to your least which in terms will lead to segmentation fault if you try to delete them. Since you don't provide more code I can't say if your Bar*s are dynamically allocated or not.
Of course it really depends on what Bar represents so the second suggestion might not be proper for the given scenario.
Btw your question shows a general lack of understanding how pointers work and is in fact not Qt related (even though your problem here is in the context of Qt). My suggestion for you would be to look up some general information on pointers in C/C++ and then move onto the containers provided by Qt.
I'm working on a game (and my own custom engine). I have quite a few assets (textures, skeletal animations, etc.) that are used by multiple models and therefore get loaded multiple times.
At first, my ambitions were smaller, game simpler and I could live with a little duplication, so shared_ptr which took care of resource cleanup once the last instance was gone seemed like a good idea. As my game grew, more and more resources got loaded multiple times and all the OpenGL state changing slowed the performance down to a crawl. To solve this problem, I decided to write an asset manager class.
I'm using an unordered_map to store a path to file in std::string and c++11's shared_ptr pointing to the actual loaded asset. If the file is already loaded, I return the pointer, if not, I call the appropriate Loader class. Plain and simple.
Unfortunately, I can't say the same about removal. One copy of the pointer remains in the unordered_map. Currently, I iterate through the entire map and perform .unique() checks every frame. Those pointers that turn out to be unique, get removed from the map, destroying the last copy and forcing the destructor run and do the cleanup.
Iterating through hundreds or thousands of objects is not the most efficient thing to do. (it's not a premature optimization, I am in optimization stage now) Is it possible to somehow override the shared pointer functionality? For example, add an "onLastRemains" event somehow? Maybe I should iterate through part of the unordered_map every frame (by bucket)? Some other way?
I know, I could try to write my own reference counted asset implementation, but all current code I have assumes that assets are shared pointers. Besides, shared pointers are excellent at what they do, so why re-invent the wheel?
Instead of storing shared_ptrs in the asset manager's map(see below, use a regular map), store weak_ptrs. When you construct a new asset, create a shared_ptr with a custom deleter which calls a function in the asset manager which tells it to remove this pointer from it's map. The custom deleter should contain the iterator into the map of this asset and supply that iterator when telling the asset manager to delete it's element from the map. The reason a weak_ptr is used in the map is that any subsequent requests for this element can still be given a shared_ptr (because you can make one from a weak_ptr) but the asset manager doesn't actually have ownership of the asset and the custom deleter strategy will work.
Edit: It was noted below the above technique only works if you use a std::map not a std::unordered_map. My recommendation would be to still do this, and switch to a regular map.
Use a std::unique_ptr in your unordered_map of assets.
Expose a std::shared_ptr with a custom deleter that looks up said pointer in the unordered_map, and either deletes it, or moves it to a second container "to be deleted later". Remember, std::shared_ptr does not have to actually own the data in question! The deleter can do any arbitrary action, and can even be stateful.
This lets you keep O(1) lookups for your assets, bunch cleanup (if you want to) instead of doing cleanup in the middle of other scenes.
You can even support temporary 0 reference count without deleting as follows:
Create a std::make_shared in the unordered_map of assets.
Expose custom std::shared_ptr. These hold a raw T* in the data, and the deleter holds a copy of the std::shared_ptr in the asset map. It "deletes" itself by storing the name (which it also holds) into a central "to be deleted" list.
Then go over said "to be deleted" list and check if they are indeed unique() -- if not, it means someone else in the meantime has spawned one of the "child" std::shared_ptr< T*, std::function<void(T*)>>s.
The only downside to this is that the type of exposed std::shared_ptr is no longer a simple std::shared_ptr.
Perhaps something like this?
shared_ptr<assed> get_asset(string path) {
static map<string, weak_ptr<asset>> cache;
auto ap = cache[path].lock();
if(!ap) cache[path] = ap = load_asset(path);
return ap;
}
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.
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.