operator delete problem.

C

ct

Hi,

Here is my problem: I need to be able to call a virtual method when an
object is deleted.

class A
{
public:
virtual ~A();
void virtual DestroyRespond();
};

class B : public A
{
public:
virtual ~B();
void virtual DestroyRespond();
};



A::~A()
{
DestroyRespond();
}

void A::DestroyRespond()
{
printf("destruction of A\n");
}

B::~B()
{

}

void B::DestroyRespond()
{
printf("destruction of B\n");
A::DestroyRespond();

}


int main(int argc, char* argv[])
{
B *b = new B();

delete b;
}


obviously this will never work, the virtual method of object B will
never get called on the destruction of B.

Is there a way ""overloading the operator delete"" for example that will
solve my problem.

here is one of the limitation cannot call A::eek:perator delete b; i need
this to be transparent as part of a framework. I also know that with a
smart_pointer this could be solve but i also neet the contruction of B
to be standart.

the framework needs to be standart

B *b = new B();
delete b;


the ouput will need to be

destruction of B
destruction of A


thanks.
 
A

Alf P. Steinbach

* ct:
[description of "virtual clean-up" problem]

I'm 75% sure that this is really just confusion over the way destructors
work, in which case a solution would be

struct A
{
virtual ~A() { std::cout << "A destroyed.\n"; }
};

struct B: A
{
virtual ~B() { std::cout << "B destroyed.\n"; }
};

which for destruction of a B object outputs both messages, B's first.

However, there is a 25% chance, or thereabouts, that you're referring to the
destruction analogoue of dynamic binding during construction, FAQ item 23.4.

And if so the solutions are essentially the same.
 
K

Karl Heinz Buchegger

ct said:
Hi,

Here is my problem: I need to be able to call a virtual method when an
object is deleted.

That won't work.
When the base class destructor runs, the derived class portion of that
object has been destroyed already. The object is no longer from derived
class type, but is a base class object.
B *b = new B();
delete b;

the ouput will need to be

destruction of B
destruction of A

class A
{
public:
virtual ~A();
void DestroyRespond();
};

class B : public A
{
public:
virtual ~B();
void DestroyRespond();
};

A::~A()
{
DestroyRespond();
}

void A::DestroyRespond()
{
printf("destruction of A\n");
}

B::~B()
{
DestroyRespond();
}

void B::DestroyRespond()
{
printf("destruction of B\n");
}

The DestroyRespond functions are called exactly in the
order you want them.
 
M

Martin Vorbrodt

This works (although little different than yours) :

#include <iostream>
using namespace std;

class A {
public:
virtual ~A() {
DestroyRespond();
}

virtual void DestroyRespond() {
cout << "~A" << endl;
}
};

class B : public A {
public:
virtual ~B() {
DestroyRespond();
}

virtual void DestroyRespond() {
cout << "~B" << endl;
}
};

int main() {
B* b = new B;
A* a = new B;
delete b;
delete a;
return 0;
}

you have to call DestroyRespond in ~B.
see, objects are constructed starting from the top most base constructor,
and destructed starting with the bottom most destructor. so, by the time you
get to the ~A, the B part of the object is long gone, and so is the type
info, therefore virtual A::DestroyRespond will be called in ~A, simply
because B doesn't exist anymore.

hope that helps
 
C

ct

I understand that calling DestroyRespond on B would solve my problem,
but i do not want to this, to hard to maintain and very confusing for
junior programmer that are new to the api.

Charles.
 
C

ct

That won't work.
When the base class destructor runs, the derived class portion of that
object has been destroyed already. The object is no longer from derived
class type, but is a base class object.
I know, this is exacly what i'm asking , is there a way to make this
architechture workable.
 
F

Frank Chang

ct, I just tried overriding the operator delete for your class B

void B::eek:perator delete(void* deadObject)
{
// deallocate B part of deadObject
// deallocate A part of deadObject
}

However, void BMary::eek:perator delete(void* deadObject) is a static
member function so you can't explicitly invoke the virtual destructors
of A and B. You can use the global operator delete (i.e. ::delete
deadObject) but I don't think this what you want.
This means that you hypothetically would have to first
deallocate the B part of the deadObject pointer, followed by the A part
of the deadObject pointer. This task is highly problematic because the
layout of objects in memory is highly compiler dependent so it would be
hard to extract the B part and A part of the deadObject pointer.
 
G

Greg

ct said:
Hi,

Here is my problem: I need to be able to call a virtual method when an
object is deleted.

class A
{
public:
virtual ~A();
void virtual DestroyRespond();
};

class B : public A
{
public:
virtual ~B();
void virtual DestroyRespond();
};



A::~A()
{
DestroyRespond();
}

void A::DestroyRespond()
{
printf("destruction of A\n");
}

B::~B()
{

}

void B::DestroyRespond()
{
printf("destruction of B\n");
A::DestroyRespond();

}


int main(int argc, char* argv[])
{
B *b = new B();

delete b;
}


obviously this will never work, the virtual method of object B will
never get called on the destruction of B.

Is there a way ""overloading the operator delete"" for example that will
solve my problem.

here is one of the limitation cannot call A::eek:perator delete b; i need
this to be transparent as part of a framework. I also know that with a
smart_pointer this could be solve but i also neet the contruction of B
to be standart.

the framework needs to be standart

B *b = new B();
delete b;


the ouput will need to be

destruction of B
destruction of A


thanks.

Why not just move whatever code is in A::DestroyRespond() into A::~A()
and move whatever code is in B::DestroyRespond() into B::~B()?

These two routines are presumably only ever called from one point in
the code, so why make two class methods distinct from the classes'
destructors?

Greg
 
D

Dan Cernat

Do not toppost!
reformatted

I understand that calling DestroyRespond on B would solve my problem,
but i do not want to this, to hard to maintain and very confusing for
junior programmer that are new to the api.

Charles.


Let's assume that what you want (call virtual function in destructor) is
possible. Still the junior programmer would have to provide the virtual
DestroyResponse method in the derived class. Isn't this as hard to maintain
as the solution above? Why not implement the actions of DestroyResponse
directly in the body of destructor? A good example of this approach is the
asignment operator and copy constructor. In 99% of the cases they both do
the same thing. How about changing the name of DestroyResponse into Cleanup
or Clear?

/dan
 
K

Karl Heinz Buchegger

Dan said:
Let's assume that what you want (call virtual function in destructor) is
possible. Still the junior programmer would have to provide the virtual
DestroyResponse method in the derived class. Isn't this as hard to maintain
as the solution above? Why not implement the actions of DestroyResponse
directly in the body of destructor? A good example of this approach is the
asignment operator and copy constructor. In 99% of the cases they both do
the same thing. How about changing the name of DestroyResponse into Cleanup
or Clear?

Agreed.
Besides that. Isn't one of the main abilities, that a junior programmer
has to learn, the ability of discipline? That includes: doing things the
way they are supposed to be done.

Moving that code into the destructor isn't really rocket sience and I wouldn't
call it: 'to hard to maintain and very confusing'. It is just normal C++
practice. If a junior programmer cannot be tought this, maybe that junior is
the wrong person for programming C++.

Don't get me wrong. I am all with the OP, to make things as easy as possible.
But there are always basic things that every involved person must be able
to do when doing X. Working with destructors in C++ is such a thing.
 
A

annamalai.gurusami

ct wrote:

(snip)
class A
{
public:
virtual ~A();
void virtual DestroyRespond();
};

class B : public A
{
public:
virtual ~B();
void virtual DestroyRespond();
};



A::~A()
{
DestroyRespond();
}

void A::DestroyRespond()
{
printf("destruction of A\n");
}

B::~B()
{

}

void B::DestroyRespond()
{
printf("destruction of B\n");
A::DestroyRespond();

}


int main(int argc, char* argv[])
{
B *b = new B();

delete b;
}

Such a design is also potentially harmful. For example,

int main(int argc, char* argv[])
{
A *a = new B();
a->DestroyRespond(); // Cleanup Done
// or so the programmer thought
}

or

int main(int argc, char* argv[])
{
A *a = new B();
a->DestroyRespond();
delete a; // DestroyRespond() Called again. May not be good news.
}
 

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
474,431
Messages
2,571,678
Members
48,796
Latest member
Greg L.

Latest Threads

Top