Pointers, Vectors, and Destructors

J

joevandyk

Below, I have a class Container that contains a vector. The vector
contains pointers to a Base class. When the Container destructor is
called, I would like to delete all the objects that the pointers in the
vector are pointing to.

It works fine, IF I comment out the destructors in Base and Inherited.
If I leave the explicit destructors in there, it seg faults. Why is
there a difference?


Thanks,
Joe



#include <iostream>
#include <vector>

using namespace std;

struct Base {
virtual ~Base() {}
};

struct Inherited : public Base {
~Inherited() {}
};

class Container
{
public:
vector<Base*> v;

~Container()
{
// Need to delete pointed-to objects in v
for (vector<Base*>::iterator i = v.begin();
i != v.end();
++i)
{
cout << "Deleting " << *i << endl;
delete *i;
}
}
};

int main()
{
Container c;

Inherited *f = new Inherited();

// Adding two pointers to the same object to Container
c.v.push_back(f);
c.v.push_back(f);

return 0;
}
 
V

Victor Bazarov

Below, I have a class Container that contains a vector. The vector
contains pointers to a Base class. When the Container destructor is
called, I would like to delete all the objects that the pointers in the
vector are pointing to.

It works fine, IF I comment out the destructors in Base and Inherited.
If I leave the explicit destructors in there, it seg faults. Why is
there a difference?

None whatsoever. Your program produces undefined behaviour in both
cases. See below.
Thanks,
Joe



#include <iostream>
#include <vector>

using namespace std;

struct Base {
virtual ~Base() {}
};

struct Inherited : public Base {
~Inherited() {}
};

class Container
{
public:
vector<Base*> v;

~Container()
{
// Need to delete pointed-to objects in v
for (vector<Base*>::iterator i = v.begin();
i != v.end();
++i)
{
cout << "Deleting " << *i << endl;
delete *i;
}
}
};

int main()
{
Container c;

Inherited *f = new Inherited();

// Adding two pointers to the same object to Container
c.v.push_back(f);
c.v.push_back(f);

How many pointers to the _same_ object does 'c.v' now contain? How
many times will you attempt to delete that object?
return 0;
}

V
 
J

joevandyk

Victor said:
None whatsoever. Your program produces undefined behaviour in both
cases. See below.


How many pointers to the _same_ object does 'c.v' now contain? How
many times will you attempt to delete that object?

c.v has two pointers to the same object. I try to delete the object
twice.

I agree, bad thing, but was wondering why it seemed to work without
explicit destructors.

Is there a way to tell whether or not a pointed-to object has been
deleted?
 
V

Victor Bazarov

[...]
c.v has two pointers to the same object. I try to delete the object
twice.

I agree, bad thing, but was wondering why it seemed to work without
explicit destructors.

Why anything _seems_? Probably because we have a tendency to believe
something we really want... Not relevant to C++ of course, but simply
specific to human psyche.
Is there a way to tell whether or not a pointed-to object has been
deleted?

No, there is no generic way. There may be a way on your platform or
in your RT library, but C++ does not provide any mechanism.

V
 
A

alexmdac

Is there a way to tell whether or not a pointed-to object has been
deleted?

You could maintain a set of deleted pointers and use this to ensure
that you don't call delete with the same pointer twice.

Like this:

~Container()
{
std::set< Base * > deleted;

// Need to delete pointed-to objects in v
for (vector<Base*>::iterator i = v.begin();
i != v.end();
++i)
{
if( deleted.find( *i ) == deleted.end() )
{
cout << "Deleting " << *i << endl;
delete *i;

deleted.insert( *i );
}

}
}
 
J

Jonathan Mcdougall

Below, I have a class Container that contains a vector. The vector
contains pointers to a Base class. When the Container destructor is
called, I would like to delete all the objects that the pointers in the
vector are pointing to.

It works fine, IF I comment out the destructors in Base and Inherited.
If I leave the explicit destructors in there, it seg faults. Why is
there a difference?

That's undefined behavior, as you are deleting an object twice. What's
happening then depends on what your implementation does in that case.

I assume you are asking about this specific behavior and that you know
you deleted an object more than once.

It seems that when you don't define a destructor in a class having no
data member (such as Inherited or Base), *your implementation* generates
none so no function gets called when an object is destroyed. That's an
optimization.

By defining a destructor by hand, you force *your implementation* to
call your destructor. Therefore, in the first scenario, there are no
calls to destructors. In the second one, destructors are called.

If you delete an object twice in the first scenario, no crash occurs
since you are not using the deallocated memory because you don't call
destructors. *Your implementation* does not not crash when deallocating
memory twice.

If you delete an object twice in the second scenario, a crash occurs
since you are calling a function (a destructor in that case) on
deallocated memory.

Both scenario are invalid from a standard C++ point of view since you
are deleting an object more than once. This situation is exactly what
we call "undefine behavior": anything could happen.


For your specific case, since you have a container of pointers which you
must delete, I would use a std::set, which allows no duplicates. That
will prevent such misusage.

Jonathan
 
?

=?iso-8859-1?q?Stephan_Br=F6nnimann?=

You can actually avoid similar problems if you use std::auto_ptr
whenever the ownership
of a pointer changes.
And of course you'll need a copy constructor and assignment operator as
well
(or prevent them as shown below).

#include <memory>
class Container {
public:
// ...
void push_back(std::auto_ptr<Base*> base) {
v.push_back(base.release(); }
private:
// prevent copying: not implemented:
Containter(const Container&);
// prevent assignment: not implemented:
Container& operator=(const Container&);
private:
vector<Base*> v;
};

Alternatively boost provides boost::shared_ptr.

Regards,
Stephan Brönnimann
(e-mail address removed)
http://www.osb-systems.com
Open source rating and billing engine for
communication networks.
 
P

PKH

Is there a way to tell whether or not a pointed-to object has been
deleted?

Do a search on Smartpointers. They are good for this kind of thing, by
doing reference counting, or by integrating smartpointers with the delete
operator.

PKH
 
L

Lionel B

Jonathan said:
/.../

For your specific case, since you have a container of
pointers which you must delete, I would use a std::set,
which allows no duplicates. That will prevent such misusage.

Unless, of course, the OP wants/needs (for whatever reason) to allow
mutiple pointers to the same object. In which case some kind of
reference counting (smart pointer?) is probably the way to go.
 
D

Duane

Below, I have a class Container that contains a vector. The vector
contains pointers to a Base class. When the Container destructor is
called, I would like to delete all the objects that the pointers in the
vector are pointing to.

It works fine, IF I comment out the destructors in Base and Inherited.
If I leave the explicit destructors in there, it seg faults. Why is
there a difference?

What if you call clear() on the vector after the delete and
before pushing back more pointers?

How about one of the boost smart pointers?
 
R

Ron Natalie

deleted?

You could maintain a set of deleted pointers and use this to ensure
that you don't call delete with the same pointer twice.

That's also undefined behavior. You're not allowed to use the
value of a deleted pointer.
 

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

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top