delete MyClass doing more than MyClass::operator delete()?

T

tom

Hi,
I'm overriding my operator new and operator delete for two classes,
one inherited from the other, so I can use my own memory pool. A
simplified version of what I have is below:


class BaseClass {
BaseClass();
virtual ~BaseClass();
virtual void baseFunction();
static void operator delete(void* mem);
};

class InheritedClass : public BaseClass {
IneritedClass();
~InheritedClass();
void baseFunction();
void nonBaseFunction();
static void operator delete(void* mem);
};


I'm testing some things by making operator delete() do nothing, so the
memory shouldn't be deallocated. I've also made the ~BaseClass() and
~InheritedClass() functions do nothing. When I call delete on an
InheritedClass object, if I try to then call any inherited function on
that object (in this example, baseFunction()) I get a crash. If I call
a non-inherited function (nonBaseFunction() in this example) then it
goes along fine and nothing bad happens, as I would epect the inherited
function to have done (since, again, no memory should be deallocated).
In my actual code, I've tested to make sure that the delete call is
actually going through my InheritedClass's operator delete function,
and that it isn't doing anything in the base class's operator delete
function, though both have them defined to do nothing. But it seems
that delete is doing something more than what I define in that
function, and it's messing up things dealing with inheritance. I'm
using Visual Studio 2005. Any ideas would be greatly appreciated.

Tom
 
V

Victor Bazarov

tom said:
I'm overriding my operator new and operator delete for two classes,
one inherited from the other, so I can use my own memory pool. A
simplified version of what I have is below:


class BaseClass {
BaseClass();
virtual ~BaseClass();
virtual void baseFunction();
static void operator delete(void* mem);
};

class InheritedClass : public BaseClass {
IneritedClass();
~InheritedClass();
void baseFunction();
void nonBaseFunction();
static void operator delete(void* mem);
};


I'm testing some things by making operator delete() do nothing, so the
memory shouldn't be deallocated. I've also made the ~BaseClass() and
~InheritedClass() functions do nothing. When I call delete on an
InheritedClass object, if I try to then call any inherited function on
that object (in this example, baseFunction()) I get a crash. If I
call a non-inherited function (nonBaseFunction() in this example)
then it goes along fine and nothing bad happens, as I would epect the
inherited function to have done (since, again, no memory should be
deallocated). In my actual code, I've tested to make sure that the
delete call is actually going through my InheritedClass's operator
delete function, and that it isn't doing anything in the base class's
operator delete function, though both have them defined to do
nothing. But it seems that delete is doing something more than what
I define in that function, and it's messing up things dealing with
inheritance. I'm using Visual Studio 2005. Any ideas would be
greatly appreciated.

Calling non-static member functions for an object after its lifetime
ended has *undefined behaviour* according to the language specification.
What else do you need to know about it?

If you'd like to learn what your code does under the covers, by all
means, explore the generated machine code and make your own conclusions
from that. However, it has no relevance here, in comp.lang.c++. Any
conclusion you make from looking at machine code is only relevant to
your particular platform (hardware and OS) and your particular compiler
implementation.

V
 
P

petke

My guess is that the compiler destroys the vtable on its own. So the
vtable pointer in your object now points to memory that has been
destroyed. Programmers dont have access to the vtable so they cant be
excpected to create and destroy it when writing their own new and
delete. The programmers part is creating or destroying the object, not
its vtable.

Since baseFunction is a virtual function it crashes when trying to
access the vtable, the nonBaseFunction does not use the vtable so does
not crash.

Using an object after calling delete (even an empty one) sure sounds
like undefined behaviour to me.

Then again I'm no expert.

Regards /Petke
 
R

Ron Natalie

tom wrote:

Despite the unfortunate and stupid name, the functions operator new and
operator delete are not the implementation of the new and delete
operators. They are the memory allocator/deallocator functions.
I'm testing some things by making operator delete() do nothing, so the
memory shouldn't be deallocated.

The memory is not deallocationed.
f I try to then call any inherited function on
that object (in this example, baseFunction()) I get a crash.

Unfortunately, just stubbing out the destructors and the delete
operators do not totally negate the operation of the delete
operator.

There are a number of things that happen during initialization
and destruction other than the invocation of the destructor
bodies and the call to operator delete() to return memory.

The truth of the matter as far as the standard is concerned
is that once the objects lifetime is over, you can't do
stuff with it. Yes you could look at the deleted memory
directly, but the object will not necessarily support any
attempts to use it as an object.

I can tell you why it probably blows up in practice, but that
knowledge is dangerous to you. You should not touch the
object after it has been deleted.


If you want to manage an object lifetime, the key is to not
use the allocation / deallocation functions. For instance,
if you want to reference count the object, you just add
functions to INCREASE/DECREASE and let the decrease delete
the object on last use:

class Counted {
public:
Counted() : references(0) { } // init reference count
private:
~Counted() { } // no external destruction.

public:
void AddReference() { ++references; }
void SubReference() { if(--reference == 0) delete this; }
};

If you want to use normal object creation / destruction procedures, you
can wrap this whole thing with a helper object that holds a pointer
to Counted and increases and decreases the reference count in it's
constructors, copy constructor, assignment operator, and destructor.

There's several of these type objects already defined and debugged
for you in the boost library.
 
P

Protoman

Ron said:
tom wrote:

Despite the unfortunate and stupid name, the functions operator new and
operator delete are not the implementation of the new and delete
operators. They are the memory allocator/deallocator functions.


The memory is not deallocationed.


Unfortunately, just stubbing out the destructors and the delete
operators do not totally negate the operation of the delete
operator.

There are a number of things that happen during initialization
and destruction other than the invocation of the destructor
bodies and the call to operator delete() to return memory.

The truth of the matter as far as the standard is concerned
is that once the objects lifetime is over, you can't do
stuff with it. Yes you could look at the deleted memory
directly, but the object will not necessarily support any
attempts to use it as an object.

I can tell you why it probably blows up in practice, but that
knowledge is dangerous to you. You should not touch the
object after it has been deleted.


If you want to manage an object lifetime, the key is to not
use the allocation / deallocation functions. For instance,
if you want to reference count the object, you just add
functions to INCREASE/DECREASE and let the decrease delete
the object on last use:

class Counted {
public:
Counted() : references(0) { } // init reference count
private:
~Counted() { } // no external destruction.

public:
void AddReference() { ++references; }
void SubReference() { if(--reference == 0) delete this; }
};

If you want to use normal object creation / destruction procedures, you
can wrap this whole thing with a helper object that holds a pointer
to Counted and increases and decreases the reference count in it's
constructors, copy constructor, assignment operator, and destructor.

There's several of these type objects already defined and debugged
for you in the boost library.

Here's a thread on this *interesting* subject:

http://groups.google.com/group/comp...q=reference+counting&rnum=11#2d300689619ed391
 
T

tom

Ah, thanks so much for this clarification. It is an unfortunate and
stupid name for these operators, I've been using them for a long time
assuming that I was completely overriding the delete functionality and
just now came to a spot where it was clear I wasn't. Very helpful
remarks, thank you all very much!!
 

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,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top