C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Polymorphic delete and iterators

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
Sideswipe
Guest





PostPosted: Fri Nov 17, 2006 8:01 am    Post subject: Polymorphic delete and iterators Reply with quote



Say I have a map<key,MyObject*> myMap;

and I add to it:

myMap[1] = new MyObjectA(..);
myMap[2] = new MyObjectB(..);
myMap[3] = new MyObjectC(..);

presume that 'MyObjectX' is a subclass of MyObject -- and and now I do:

map<key,MyObject*>::iterator itr;
for(itr = objects.begin(); itr != objects.end(); ++itr){
delete itr->second;
}
Will this delete everything properly or is it going to delete based on
the pointer from the virtual table? (and thus dangling and or
corrupting memory)

Christian

http://christian.bongiorno.org


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Salt_Peter
Guest





PostPosted: Fri Nov 17, 2006 10:10 am    Post subject: Re: Polymorphic delete and iterators Reply with quote



Sideswipe wrote:
Quote:
Say I have a map<key,MyObject*> myMap;

and I add to it:

myMap[1] = new MyObjectA(..);
myMap[2] = new MyObjectB(..);
myMap[3] = new MyObjectC(..);

presume that 'MyObjectX' is a subclass of MyObject -- and and now I do:

map<key,MyObject*>::iterator itr;
for(itr = objects.begin(); itr != objects.end(); ++itr){
delete itr->second;
}
Will this delete everything properly or is it going to delete based on
the pointer from the virtual table? (and thus dangling and or
corrupting memory)

Christian

Have you tried it? Why rely on what anyone says rather than proof?

#include <iostream>
#include <map>
#include <boost/shared_ptr.hpp>

struct Object
{
virtual ~Object() { std::cout << "~Object\n"; }
};

class ObjectX : public Object
{
public:
ObjectX() { std::cout << "ObjectX\n"; }
~ObjectX() { std::cout << "~ObjectX\n"; }
};

int main()
{
typedef boost::shared_ptr< Object > SharedPtrObj;
typedef std::map< int, SharedPtrObj > MType;
MType mob;

// allocate 5
for(int i = 0; i < 5; ++i)
{
boost::shared_ptr< ObjectX > sp_objx( new ObjectX );
mob.insert( std::make_pair(i, sp_objx) );
}

// show them
typedef MType::iterator MIter;
for(MIter miter = mob.begin(); miter!= mob.end(); ++miter)
{
std::cout << "key: " << (*miter).first;
std::cout << "\tp_objx: " << (*miter).second;
std::cout << std::endl;
}
}


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Gerhard Menzl
Guest





PostPosted: Fri Nov 17, 2006 10:10 am    Post subject: Re: Polymorphic delete and iterators Reply with quote



Sideswipe wrote:

Quote:
Say I have a map<key,MyObject*> myMap;

and I add to it:

myMap[1] = new MyObjectA(..);
myMap[2] = new MyObjectB(..);
myMap[3] = new MyObjectC(..);

presume that 'MyObjectX' is a subclass of MyObject -- and and now I
do:

map<key,MyObject*>::iterator itr;
for(itr = objects.begin(); itr != objects.end(); ++itr){
delete itr->second;
}
Will this delete everything properly or is it going to delete based on
the pointer from the virtual table? (and thus dangling and or
corrupting memory)

Assuming that you meant to type "myMap" where you typed "objects", this
will delete every object derived from MyObject, providing MyObject has a
public virtual destructor. It will, however, leave dangling pointers
(i.e. pointers pointing to objects that are deceased, bereft of life,
gone to meet their maker etc.) in the map.

--
Gerhard Menzl

Non-spammers may respond to my email address, which is composed of my
full name, separated by a dot, followed by at, followed by "fwz",
followed by a dot, followed by "aero".



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Ivan Novick
Guest





PostPosted: Sat Nov 18, 2006 10:10 am    Post subject: Re: Polymorphic delete and iterators Reply with quote

Quote:
MyObject is an interface and has all pure virtuals (it does not
specifiy a virtual destructor though and that would be my problem
(doesn't it need to be a 'pure' virtual dest?).
It does not need to be a pure virtual destructor, just virtual. If the

destructor of the base class is not virtual you will not call the
destructor of the derived class.

Quote:
Basically, my memory profiler/checker is telling me that the mentioned
loop is deleting memory blocks NOT at the begginning of the block. I
access these pointer as objects pointers and don't mess their addresses
at all (why would I !?). I am just trying to figure out why it's
complaining.
Try fixing your base class destructor first.


Quote:
But, you mentioned I would still have dangling pointers. To what?! I
That just means you will have pointers that still exist in the

container but don't don't point to allocated data, because you just
deleted it. If you are deleting all the objects and then clearing the
container you should be ok.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
James Kanze
Guest





PostPosted: Sat Nov 18, 2006 10:53 pm    Post subject: Re: Polymorphic delete and iterators Reply with quote

Sideswipe wrote:

Quote:
MyObject is an interface and has all pure virtuals (it does not
specifiy a virtual destructor though and that would be my problem
(doesn't it need to be a 'pure' virtual dest?).

That's definitly a problem. The rule is that if you delete an
object, either the pointer has the same type as the dynamic type
of the object, or the destructor is virtual, or you have
undefined behavior. You're in the last case.

What actually happens, of course, is that the compiler uses the
virtuality of the destructor as the signal that it must do some
special calculations to get the actual address (and even to
determine which operator delete function to use---but that's an
advanced issue). The usual implementation is for the compiler
to actually generate the call to the deallocation functions in
the destructor, with some sort of hidden flag to indicate
whether it should be called or not. And of course, this only
works if there is dynamic dispatch on the destructor.

There are no other constraints on the destructor, and in
"interfaces", I generally provide it directly inline, since it
is the only function which has a definition, and I don't really
want to create a source file just for it.

Quote:
Basically, my memory profiler/checker is telling me that the mentioned
loop is deleting memory blocks NOT at the begginning of the block.

This is typically the case if you use multiple or virtual
inheritance in anyway.

Quote:
I access these pointer as objects pointers and don't mess
their addresses at all (why would I !?).

Converting a pointer to derived to a pointer to base may modify
the physical address. Using a virtual destructor is C++'s way
of telling the compiler that it has to redo the conversion, in
reverse, in a delete statement.

Note that it's also important if any of the derived objects has
something to do in the destructor, e.g. if the derived object
contains an element of type string. You do want the destructor
of the derived object to be called. But this is, in a certain
sense secondary, since you need the virtual destructor even if
you don't have anything to do in the derived class.

Quote:
I am just trying to figure out why it's
complaining.

But, you mentioned I would still have dangling pointers. To what?!

To nothing good. That's why they're called dangling pointers.
The are not null, so you cannot test for them, but anything you
do with them is undefined behavior. Formally, that includes
even just copying them. And, technically speaking, even just
having them in a standard container.

A 100% guaranteed correct implementation of your loop would look
something like:

for ( map< Key, MyObject* >::iterator itr = objects.begin() ;
itr != objects.end() ;
itr ++ ) {
MyObject* tmp = itr->second ;
itr->second = NULL ;
delete tmp ;
}

IF this is the very last thing you are doing, prior to
destructing the map, I would'nt worry too much about it---it's
one of those undefined behaviors which in fact work everywhere,
and that no implementation would dare break because so many
users are using it. But if the map will continue to exist,
after the loop, I would definitly either set the pointers to
NULL, or remove the elements from the map, in order to avoid
future problems. (If you start removing elements from the map,
pay attention to the validity of iterators. Removing an element
under an iterator invalidates the iterator, so you need to do
something like:

map< Key, MyObject* >::iterator itr = objects.begin() ;
while ( itr != objects.end() ) {
itr = objects.erase( itr ) ;
}

or:

map< Key, MyObject* >::iterator itr = objects.begin() ;
while ( itr != objects.end() ) {
objects.erase( itr ++ ) ;
}

--
James Kanze (Gabi Software) email: james.kanze (AT) gmail (DOT) com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Salt_Peter
Guest





PostPosted: Sat Nov 18, 2006 10:59 pm    Post subject: Re: Polymorphic delete and iterators Reply with quote

James Kanze wrote:
Quote:
Salt_Peter wrote:

[...]
Have you tried it? Why rely on what anyone says rather than proof?

Perhaps because trying it only tells you what one particular
compiler happens to do in its current version, not what is
guaranteed to work. The standard library is just loaded with
ways to encounter undefined behavior, many of which happen to
work with some compilers and some implementations of the
library. As it happens, what he is doing is guaranteed, but
just trying it with one particular compiler (or even a number of
different compilers) won't tell you that.

Nobody is suggesting "trying" to verify what is and isn't UB.
Which, itself, is not learned via trial and error, as you gracefully
mentioned.
I was suggesting allocating and deallocating an instance of the class
to verify destruction.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Ron Natalie
Guest





PostPosted: Sun Nov 19, 2006 3:41 am    Post subject: Re: Polymorphic delete and iterators Reply with quote

Ivan Novick wrote:

Quote:
It does not need to be a pure virtual destructor, just virtual. If the
destructor of the base class is not virtual you will not call the
destructor of the derived class.

No, if the destructor is not virtual, you have undefined behavior.

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Ivan Novick
Guest





PostPosted: Sun Nov 19, 2006 9:33 am    Post subject: Re: Polymorphic delete and iterators Reply with quote

Ron Natalie wrote:
Quote:
Ivan Novick wrote:

It does not need to be a pure virtual destructor, just virtual. If the
destructor of the base class is not virtual you will not call the
destructor of the derived class.

No, if the destructor is not virtual, you have undefined behavior.
Right but it does not need to be a "pure" virtual i believe.



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.