Deleting elements of vectors that contain pointers to other objects

  • Thread starter dwightarmyofchampions
  • Start date
D

dwightarmyofchampions

How exactly do I delete elements of a vector in the destructor?
Suppose my vector in my class definition looks like this:

std::vector<ABC*> vec;

which means I am declaring a vector whose elements will contain
pointer to ABC objects.

....and in my constructor I have:

vec.clear(); // make sure vector is empty before populating it

for (int i = 0; i < 5; i++)
{
ABC* abcobject1 = new ABC(i);
vec.push_back(abcobject1);
}

When I go to my destructor, do I just need to pop_back() the vector
elements...

for (int i = 0; i < 5; i++)
{
vec.pop_back();
}

....or do I delete each ABC object and then pop_back its corresponding
vector pointer...

for (int i = 0; i < 5; i++)
{
delete vec; vec = 0; // or is it (*vec)???
vec.pop_back();
}

....or do I do something else? Isn't there a delete[] statement for
this sort of thing?
 
R

red floyd

How exactly do I delete elements of a vector in the destructor?
Suppose my vector in my class definition looks like this:

std::vector<ABC*> vec;

which means I am declaring a vector whose elements will contain
pointer to ABC objects.

...and in my constructor I have:

vec.clear();   // make sure vector is empty before populating it

for (int i = 0; i < 5; i++)
{
  ABC* abcobject1 = new ABC(i);
  vec.push_back(abcobject1);

}

When I go to my destructor, do I just need to pop_back() the vector
elements...

for (int i = 0; i < 5; i++)
{
  vec.pop_back();

}

...or do I delete each ABC object and then pop_back its corresponding
vector pointer...

for (int i = 0; i < 5; i++)
{
   delete vec; vec = 0; // or is it (*vec)???
   vec.pop_back();

}

...or do I do something else? Isn't there a delete[] statement for
this sort of thing?


This is a question of ownership. That's why you need to document who
owns what. If the vector is intended to own the pointers, you
probably shouldn't store raw pointer, but instead use your favorite
smart pointer.

If you're using raw pointers, you need to delete the elements
individually.

for (std::vector<ABC*>::iterator it = vec.begin();
it != vec.end();
++it)
{
delete *it;
*it = 0; // probably optional
}

If you're using smart pointers, where smart_ptr_t<> is your favorite
smart pointer:

std::vector<smart_ptr_t<ABC> > vec;
Then, when vec is deleted, it invokes the smart_ptr_t<> destructor on
every element,
and the smart_ptr_t<> destructor handles the memory management.
 
D

dwightarmyofchampions

Thanks, that was very helpful.

I've never even heard of smart pointers, so I'll have to wait on that
one.

Question about the iterator for loop: It doesn't delete the vector and
it doesn't remove the vector elements. Instead, it deletes the objects
that the vector elements point to. Now my question is, Within the for
loop do I also have to put in a vec.pop_back(); so the elements
themselves get deleted? Or will they just automatically get deleted?
And what about the vec instance itself? Do I have to worry about
that?
 
J

James Kanze

How exactly do I delete elements of a vector in the
destructor? Suppose my vector in my class definition looks
like this:
std::vector<ABC*> vec;
which means I am declaring a vector whose elements will
contain pointer to ABC objects.
...and in my constructor I have:
vec.clear(); // make sure vector is empty before populating it
for (int i = 0; i < 5; i++)
{
ABC* abcobject1 = new ABC(i);
vec.push_back(abcobject1);
}
When I go to my destructor, do I just need to pop_back() the
vector elements...
for (int i = 0; i < 5; i++)
{
vec.pop_back();
}
...or do I delete each ABC object and then pop_back its
corresponding vector pointer...
for (int i = 0; i < 5; i++)
{
delete vec; vec = 0; // or is it (*vec)???
vec.pop_back();
}
...or do I do something else? Isn't there a delete[]
statement for this sort of thing?

This is a question of ownership. That's why you need to
document who owns what. If the vector is intended to own the
pointers, you probably shouldn't store raw pointer, but
instead use your favorite smart pointer.

Sort of. If the objects in question have value semantics, and
support copy, then he probably shouldn't have a vector of
pointers to begin with. If they are entity objects, then you
have to ask the question of what their lifetime should be. In
practice, cases where the lifetime of an entity object depends
on the lifetime of a container are extremely rare.

If the lifetime does depend strictly on the container of course,
then you need to wrap the container in a class which takes care
of the deletes.
If you're using raw pointers, you need to delete the elements
individually.
for (std::vector<ABC*>::iterator it = vec.begin();
it != vec.end();
++it)
{
delete *it;
*it = 0; // probably optional
}

Actually, formally speaking, even that's undefined behavior.
Formally, you can't touch the vector once you've done the
delete; you have to erase the element, or replace it with a null
pointer, first.

Practically, if this code is in the destructor of the object
containing the vector, I wouldn't worry about it.
If you're using smart pointers, where smart_ptr_t<> is your
favorite smart pointer:
std::vector<smart_ptr_t<ABC> > vec;
Then, when vec is deleted, it invokes the smart_ptr_t<>
destructor on every element, and the smart_ptr_t<> destructor
handles the memory management.

Supposing it's that type of smart pointer:). (Don't forget
that smart pointers are used for other things, such as managing
locks.) This is a workable solution, but it's usually overkill,
and you have to pay attention to the semantics of the
smart_ptr---those which would seem to have the appropriate
semantics (e.g. auto_ptr) often don't work in containers.
 
J

James Kanze

You should check 'em out; they're wonderful. I've just
recently used Boost's shared_ptr.hpp for the first time, and
it was great for this kind of thing. Maybe the coding almost
as nice as it would be in Java. :)

For trivial cases, perhaps. For any real applications, it's a
guaranteed recepe for memory leaks and accessing already freed
memory.
 
A

Alf P. Steinbach

* James Kanze:
For trivial cases, perhaps. For any real applications, it's a
guaranteed recepe for memory leaks and accessing already freed
memory.

All righty (or rather, not, but...), you use the Boehm garbage collector, and as
I understand it you use strict hierarchical ownership and strict adherence to
conventions for that (for other resources than memory), and it works for you.

And it would be wonderful (hope that's not too femmy language) if you could put
up a short tutorial or something on that. Because statistically speaking almost
no-one else -- in fact, I know only about you -- have managed this. And I
think that when the steep & long learning curve one fears is present, is
removed, it could be Really Useful.

But having mastered such a difficult but quite probably very elegant and
efficient technique, I find it incredible that you have problems with smart
pointers, or that your co-workers have. If it's you, then it just doesn't make
sense, it's sort of impossible. And if it's your co-workers, well then, how the
heck do they then manage do to things right when they have to do all non-memory
lifetime management manually (as with garbage collection sans smart pointers)?


Wondering,

- Alf
 
I

Ian Collins

James said:
For trivial cases, perhaps. For any real applications, it's a
guaranteed recepe for memory leaks and accessing already freed
memory.

Um, just about every non-trivial application I've written over the past
few years (some running 24/7 managing business critical servers) make
extensive use of smart pointers. None leak or access already freed
memory.

I must be doing something wrong.
 
J

James Kanze

* James Kanze:
All righty (or rather, not, but...), you use the Boehm garbage
collector,

When I can. For a number of reasons, that's not as often as I'd
like.
and as I understand it you use strict hierarchical ownership
and strict adherence to conventions for that (for other
resources than memory), and it works for you.

No, I don't use a strict hierarchical ownership. In most cases,
dynamically allocated objects own themselves, and assume the
responsibility for managing their lifetime.
And it would be wonderful (hope that's not too femmy language)
if you could put up a short tutorial or something on that.
Because statistically speaking almost no-one else -- in
fact, I know only about you -- have managed this.

Are you kidding. I've worked on a number of projects, in a
number of different companies and organizations, and I've never
once seen one which used smart pointers when I arrived. I've
been the one which introduced them, for the special cases where
they apply, but generally, the only pointers are this and for
navigation. The this pointer can't be a smart pointer, and
there's no need for smart pointers for navigation.

Having heard so much good about Boost::shared_ptr, I did try to
introduce it into one application. The result was that we
immediately started leaking memory (due to cycles). And it's
far too easy to end up with two counters for a single
object---in cases where a reference counted pointer is
appropriate (which aren't as many as people seem to think), an
invasive pointer which stores the counter in the pointed to
object is far safer.
And I think that when the steep & long learning curve one
fears is present, is removed, it could be Really Useful.
But having mastered such a difficult but quite probably very
elegant and efficient technique, I find it incredible that you
have problems with smart pointers, or that your co-workers
have.

Incredible or not, those are the facts.
If it's you, then it just doesn't make sense, it's sort of
impossible. And if it's your co-workers, well then, how the
heck do they then manage do to things right when they have to
do all non-memory lifetime management manually (as with
garbage collection sans smart pointers)?

Well, smart pointers don't work when the lifetime has to be
explicitly managed, and is arbitrary. And in other cases, you
don't use dynamic allocation (except in such low level things
like string and vector---but since the pointers are internal to
the object, you don't need smart pointers there). There are
certainly exceptions---I generally design my agents so that they
are managed by an invasive smart pointer. But they're just
that, exceptions.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,705
Latest member
Stefkari24

Latest Threads

Top