Sign in to follow this  

STL list question [SOLVED]

This topic is 3851 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

if I were to create a list and populate it like so

Magnus_SubMain* NewSubMain = NULL;

for(DWORD d = 0; d < m_dwNumProcessors; d++)
{
	NewSubMain = new Magnus_SubMain;

	MagnusSubMain_List.push_back(NewSubMain);
}




would a simple list.clear() function delete the memory I allocated or would I have to do this?:

std::list<Magnus_SubMain*>::iterator SM_it = MagnusSubMain_List.begin();

while(SM_it != MagnusSubMain_List.end())
{
	delete (*SM_it);
	SM_it++;
}



[Edited by - etsuja on May 25, 2007 8:25:57 PM]

Share this post


Link to post
Share on other sites
The list (just like any other well-written container class) cleans up after itself. Nothing more, nothing less.
In other words, any memory allocated by the list (using new) will be freed again (using delete)

Anything you do is your responsibility.

In your example, all you give the list is a pointer. How should it know whether that pointer was new'ed? It might point to something on the stack, and so it shouldn't be deleted.

And more importantly, it might point to something you don't actually want destroyed yet! You might get rid of the list, yes, but still want to use the elements it contained. Hard to do that if the list automatically deletes everything it touches.

So as always, the rule is that you delete the memory you allocate. And you assume that any third-party code (including the standard library) does the same.

Edit: Of course, in your example, there's no need to use new at all. You could just populate the list like this:


for(DWORD d = 0; d < m_dwNumProcessors; d++) {
MagnusSubMain_List.push_back(Magnus_SubMain()); // <- no calls to 'new' at all
}

And then, since you haven't actually new'ed anything, you don't need to delete anything when the list is destroyed either.

[Edited by - Spoonbender on May 25, 2007 8:35:48 PM]

Share this post


Link to post
Share on other sites
You have to delete the memory yourself. You new it, you delete it. Least with the SC++L.

And you can save a line of code:

NewSubMain = new Magnus_SubMain;

MagnusSubMain_List.push_back(NewSubMain);



to


MagnusSubMain_List.push_back(new Magnus_SubMain);

Share this post


Link to post
Share on other sites
These two posts have me confused...

so if I use this way the library will delete it for me?

MagnusSubMain_List.push_back(new Magnus_SubMain);


and this way it wont?

NewSubMain = new Magnus_SubMain;

MagnusSubMain_List.push_back(NewSubMain);

Share this post


Link to post
Share on other sites
Those are basically the same you allocated them so you have to delete them by looping and calling delete on each. What you need to look out for is that those pointers are not passed around your app and used at some point after you have deleted them.

Share this post


Link to post
Share on other sites
Quote:
Original post by etsuja
These two posts have me confused...

so if I use this way the library will delete it for me?

MagnusSubMain_List.push_back(new Magnus_SubMain);


and this way it wont?

NewSubMain = new Magnus_SubMain;

MagnusSubMain_List.push_back(NewSubMain);


Every time you have a 'new' in your code, you need to call 'delete'.
Note that in my example, there was no 'new' at all. The variable is created on the stack, and stored in the list (which then has to have type std::list<Magnus_SubMain>, without the *)

When the list is destroyed, it calls the destructor on the elements it contains. In your code, it only contains pointers, and they don't have a destructor. All that happens to them is that they.. go away. It doesn't touch what the pointers point to. (Because it can't know whether the objects they point to should be deleted, or even if they are valid)
But if you store the object itself in the list, the object's destructor will be called when the list is destroyed. And then your objects will be destroyed for you.

Share this post


Link to post
Share on other sites
Righteous, thanks for the info guys. I guess I should have rememberd when I first learned about new which I do now that it sad for every new there must be a delete.

@Spoonbender: I think I will do it that way since the elements don't have to be in dynamic memory.

Share this post


Link to post
Share on other sites
If you are keeping pointers to things in an STL container and you know that the container will always 'own' the pointers you can implement a templated deletion functor that, in combination with for_each, will delete everything safely. This could be used in a 'clear resources' function, or a containing object's destructor if you know that the resources' lifetimes shouldn't outlast the container.


template <typename T>
struct PtrCollectionDelete
{
void operator()(T * target) { delete target; target = NULL; }
};

// Assuming you have e.g. a std::vector<Resource*> resources then to delete them all you can use

std::for_each(resources.begin(),
resources.end(),
PtrCollectionDelete<Resource>());




(Haven't checked this code btw, but should be OK I think.)

L
-

Share this post


Link to post
Share on other sites
Quote:
Original post by PKLoki
If you are keeping pointers to things in an STL container and you know that the container will always 'own' the pointers you can implement a templated deletion functor that, in combination with for_each, will delete everything safely. This could be used in a 'clear resources' function, or a containing object's destructor if you know that the resources' lifetimes shouldn't outlast the container.

*** Source Snippet Removed ***

(Haven't checked this code btw, but should be OK I think.)

L
-


You are setting a copy of the pointer to NULL, which is ineffectual. You would need to pass the pointer by reference in order to modify the value in the container. The standard is fuzzy on the legality of doing that, though, so you would probably end up using transform instead.

That said, your function object can be improved:

struct ptr_delete {
template< class T >
void operator()( T * const p ) const {
delete p;
}
};





Which will take advantage of automatic template deduction:

std::for_each( resources.begin(), resources.end(), ptr_delete() );
resources.clear()



Now, a version that would use transform() would look like this:

struct ptr_delete {
template< class T >
T * operator()( T * const p ) const {
delete p;
return 0;
}
};

// ...

std::transform( resources.begin(), resources.end(), resources.begin(), ptr_delete() );





That is, of course, assuming that you want to allow null values in your container.


All in all, one would probably be better off with the Boost Pointer Containers or a container of boost::shared_ptrs (edit: or, as Spoonbender has suggested, not use dynamic memory at all).


jfl.

Share this post


Link to post
Share on other sites
Quote:
Original post by etsuja
These two posts have me confused...

so if I use this way the library will delete it for me?

MagnusSubMain_List.push_back(new Magnus_SubMain);


and this way it wont?

NewSubMain = new Magnus_SubMain;

MagnusSubMain_List.push_back(NewSubMain);


Sorry it took me so long to reply, head cold really hit me hard.

Anyways, I stated in the first line of my original post that you new it you delete it. So I figured I didn't need to explain that. I was just showing you slightly more "efficient" way to code your allocation function. No need to make a temp variable then pass it into the list.

Share this post


Link to post
Share on other sites

This topic is 3851 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this