473,701 Members | 2,918 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Explicit destructor calls from inside base class destructor

frs
For memory economization, I need to get rid if the virtual
destructor. Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class. Briefly it could be displayed like the code below.
It ends up deleting the member 'x' of 'B' twice. Why? Is there
a way around?

Thanks

Frank

=============== =============== =============== =============== =========
#include<iostre am>
using namespace std;

struct TypeX { ~TypeX() { cerr << "destructed \n"; }
struct A { ~A(); }
struct B : public A {
TypeX x;
~B();
}

A::~A() {
// at this point, ~A knows, that 'this' points is in fact to a 'B'
// (it does! no need to say 'type-switches are bad' - there's no
other way)
delete &(static_cast<B *>(this)->x);
}

int
main(int, char**)
{
A* a = new B;
cerr << "before\n";
// somewhere, there might be someone deleting 'a'
delete a;
cerr << "after\n";
}

Sep 18 '05 #1
20 2744
* frs:
For memory economization, I need to get rid if the virtual
destructor. Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class.


Already you have told enough.

Don't.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Sep 18 '05 #2
frs wrote:
For memory economization, I need to get rid if the virtual
destructor. Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class. Briefly it could be displayed like the code below.
It ends up deleting the member 'x' of 'B' twice. Why? Is there
a way around?

Thanks

Frank

=============== =============== =============== =============== =========
#include<iostre am>
using namespace std;

struct TypeX { ~TypeX() { cerr << "destructed \n"; }
struct A { ~A(); }
struct B : public A {
TypeX x;
~B();
}

A::~A() {
// at this point, ~A knows, that 'this' points is in fact to a 'B'
// (it does! no need to say 'type-switches are bad' - there's no
other way)
delete &(static_cast<B *>(this)->x);


ITYM

static_cast<B*> (this)->x::~TypeX();

but really, I think you should choose a different language to C++ if you
memory constratints are as titght as you say they are. Perhaps you would
be better of with C.

john
Sep 18 '05 #3

frs wrote:
For memory economization, I need to get rid if the virtual
destructor. Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class. Briefly it could be displayed like the code below.
It ends up deleting the member 'x' of 'B' twice. Why? Is there
a way around?

Thanks

Frank

=============== =============== =============== =============== =========
#include<iostre am>
using namespace std;

struct TypeX { ~TypeX() { cerr << "destructed \n"; }
struct A { ~A(); }
struct B : public A {
TypeX x;
~B();
}

A::~A() {
// at this point, ~A knows, that 'this' points is in fact to a 'B'
// (it does! no need to say 'type-switches are bad' - there's no
other way)
delete &(static_cast<B *>(this)->x);
}

int
main(int, char**)
{
A* a = new B;
cerr << "before\n";
// somewhere, there might be someone deleting 'a'
delete a;
cerr << "after\n";
}


You can avoid using a virtual destructor if you use the following smart
pointer (cow_ptr) class:
http://code.axter.com/cow_ptr.h

However, IMHO, you're not going to save much by removing the virtual
destructor.

Sep 18 '05 #4
frs wrote:
For memory economization, I need to get rid if the virtual
destructor. Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class. Briefly it could be displayed like the code below.
It ends up deleting the member 'x' of 'B' twice. Why?
The destructor of B calls the destructors of all base classes to take care
of the corresponding subobjects. Thus, the destructor of A is called again.
I would be inclined to assume that this invokes undefined behavior. Anyway,
the following code shows an infinite loop on my machine:

#include <iostream>

struct A {
~A();
};

struct B : public A {

~B ( void ) {
std::cout << "desctructi ng B\n";
}

};

A::~A ( void ) {
std::cout << "desctructi ng A\n";
static_cast<B*> ( this )->~B();
}

int main ( void ) {
B b;
}

Is there a way around?


Maybe. How is anybody to tell? You did not offer that much of information
regarding what you actually want to accomplish. An item of particular
interest would be: how do you know that objects of type A* are dynamically
of type B*; and if you know that, do you really need runtime polymorphism?
[code snipped]
Best

Kai-Uwe Bux
Sep 18 '05 #5
John Harrison wrote:
frs wrote:
For memory economization, I need to get rid if the virtual
destructor. Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class. Briefly it could be displayed like the code below.
It ends up deleting the member 'x' of 'B' twice. Why? Is there
a way around?

Thanks

Frank

=============== =============== =============== =============== =========
#include<iostre am>
using namespace std;

struct TypeX { ~TypeX() { cerr << "destructed \n"; }
struct A { ~A(); }
struct B : public A {
TypeX x;
~B();
}

A::~A() {
// at this point, ~A knows, that 'this' points is in fact to a 'B'
// (it does! no need to say 'type-switches are bad' - there's no
other way)
delete &(static_cast<B *>(this)->x);

ITYM

static_cast<B*> (this)->x::~TypeX();


Soory, didn't check that the above compiled. Here's what I really meant.

#include<iostre am>
using namespace std;

struct TypeX { ~TypeX() { cerr << "destructed \n"; } };
struct A { ~A(); };
struct B : public A {
TypeX x;
~B();
};

A::~A() {
static_cast<B*> (this)->x.~TypeX();
}

int
main(int, char**)
{
A* a = new B;
cerr << "before\n";
// somewhere, there might be someone deleting 'a'
delete a;
cerr << "after\n";
}

output is

before
destructed
after

John
Sep 18 '05 #6

"frs" <fr************ **@gmx.net> wrote in message
news:11******** **************@ g49g2000cwa.goo glegroups.com.. .
For memory economization, I need to get rid if the virtual
destructor. Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class. Briefly it could be displayed like the code below.
It ends up deleting the member 'x' of 'B' twice. Why? Is there
a way around?

Thanks

Frank


From stepping through the code first you are deleting x explicitly then the
destructor of A also deletes it implicitly.

i.e. your problem seems to act as if you did the following

main()
{
TypeX x;

delete &x;

}

Try using a pointer to TypeX and see if it works better or not.

i.e.

TypeX* x;

and change

delete &(static_cast<B *>(this)->x); to

delete (static_cast<B* >(this)->x);

What seems to be the problem as I pointed out earlier is that you delete a
non-pointer and then the destructor deletes it too... it doesn't know that
you already deleted it and probably because the method doesn't seem very
"stable" in the sense its kinda forcing the language to do something that
doesn't seem natural(IMO). Maybe you should rething the design and see if
you can't make it more natural? Maybe you can override new and delete for
your needs?

Jon
Sep 18 '05 #7
frs wrote:
For memory economization, I need to get rid if the virtual
destructor.
Does a virtual destructor really increase your memory needs so much? Which
platform are you writing that code for, if a few bytes of memory are too
much?
Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class. Briefly it could be displayed like the code below.
It ends up deleting the member 'x' of 'B' twice. Why?
Because when the end of an object's life is reached, the destructor gets
called automatically.
Is there a way around?
Well, don't use polymorphism if the (actually quite small) overhead is too
much for your platform.
=============== =============== =============== =============== =========
#include<iostre am>
using namespace std;

struct TypeX { ~TypeX() { cerr << "destructed \n"; }
struct A { ~A(); }
struct B : public A {
TypeX x;
~B();
}

A::~A() {
// at this point, ~A knows, that 'this' points is in fact to a 'B'
// (it does! no need to say 'type-switches are bad' - there's no
other way)
If at this place, the object can only be a B, why would A need to care for
the destruction? Why would you need polymorphism at all?
delete &(static_cast<B *>(this)->x);
You must never give a pointer to delete that you didn't get from new (except
a null pointer).
}

int
main(int, char**)
{
A* a = new B;
Why do you use an A*? Above, you say that all objects are of type B. So just
use a B*.
cerr << "before\n";
// somewhere, there might be someone deleting 'a'
delete a;
cerr << "after\n";
}


Sep 18 '05 #8
"frs" <fr************ **@gmx.net> wrote in message
news:11******** **************@ g49g2000cwa.goo glegroups.com.. .
For memory economization, I need to get rid if the virtual
destructor.
You can in fact gain a miniscule amount of time by making the destructor
non-virtual, a time which probably doesn't make the application fast; but
you cannot make the application use less memory by doing that.

Actually, you may be able to shave off one function pointer from the
application :)
Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class.
You can't call the destructor of the derived class from the base class,
because the derived object doesn't exist anymore at the time the base class
destructor is called.

When the destructor of the base class is called, all of the parts of the
derived are already dead. You can't call the derived object's destructor and
expect meaningful things to happen.
struct TypeX { ~TypeX() { cerr << "destructed \n"; }
struct A { ~A(); }
struct B : public A {
TypeX x;
~B();
}

A::~A() {
// at this point, ~A knows, that 'this' points is in fact to a 'B'
// (it does! no need to say 'type-switches are bad' - there's no
other way)
Your exclamation mark above suggests that you don't completely understand
object lifetimes. In the destructor above, this points to an A and an A
alone. There is no B left at that time.
delete &(static_cast<B *>(this)->x);


Undefined behavior. If ~A is being called through the destruction of a B
object, the destructor of B is already called and is about to complete. You
cannot call it again.

Ali
Sep 18 '05 #9
John Harrison wrote:
John Harrison wrote:
frs wrote:
For memory economization, I need to get rid if the virtual
destructor. Under this constraint I get caught up in a design,
where I need to call a destructor of a derived class from a
base class. Briefly it could be displayed like the code below.
It ends up deleting the member 'x' of 'B' twice. Why? Is there
a way around?


Soory, didn't check that the above compiled. Here's what I really meant.

#include<iostre am>
using namespace std;

struct TypeX { ~TypeX() { cerr << "destructed \n"; } };
struct A { ~A(); };
struct B : public A {
TypeX x;
~B();
};

A::~A() {
static_cast<B*> (this)->x.~TypeX();
}


This rather avoids the issue; the B's destructor is never called
(and the memory for the B is never released).

Since the OP does not wish to use polymorphishm, maybe he could
make an A member variable of B, rather than using inheritance.
Then the destructor will work correctly.

Sep 19 '05 #10

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
1355
by: Robert Dick | last post by:
Derived classes sometimes need to delegate portions of the work in overridden methods to methods in their base classes. This was traditionally done with explicit calls in python, e.g., class Derived(Left, Right): def __init__(self, myarg, larg, rarg): Left.__init__(self, larg) Right.__init__(self, rarg) self.data = myarg print 'derived'
20
5984
by: qazmlp | last post by:
My class in a header file, contains inline virtual destructor. Is this Ok? Can it cause any problems? class base { public: base() { } virtual ~base { std::cout<<"Inside virtual destructor\n"; } // Other members
11
4358
by: santosh | last post by:
Hello, I was going through the Marshal Cline's C++ FAQ-Lite. I have a doubt regarding section 33.10. Here he is declaring a pure virtual destructor in the base class. And again defining it inline. Like this.
6
7962
by: Squeamz | last post by:
Hello, Say I create a class ("Child") that inherits from another class ("Parent"). Parent's destructor is not virtual. Is there a way I can prevent Parent's destructor from being called when a Child object goes out of scope? Specifically, I am dealing with a C library that provides a function that must be called to "destruct" a particular struct (this struct is dynamically allocated by another provided function). To avoid memory
5
3336
by: Frederick Gotham | last post by:
If we have a simple class such as follows: #include <string> struct MyStruct { std::string member; MyStruct(unsigned const i) {
23
2591
by: Ben Voigt | last post by:
I have a POD type with a private destructor. There are a whole hierarchy of derived POD types, all meant to be freed using a public member function Destroy in the base class. I get warning C4624. I read the description, decided that it's exactly what I want, and ignored the warning. Now I'm trying to inherit using a template. Instead of "destructor could not be generated because a base class destructor is inaccessible", I now have an...
4
2022
by: Subra | last post by:
Hi, I am learning C++ and need export advice on the below program. I have read it that whenever a exception is genrated and control enteres the catch block it will call destructors for all the successfuly completed constructors. But in the below case i am doing :- base *ptr=new base; throw 44; But the destructor for base is not called once it enters the catch
12
7202
by: Rahul | last post by:
Hi Everyone, I have the following code and i'm able to invoke the destructor explicitly but not the constructor. and i get a compile time error when i invoke the constructor, why is this so? class Trial { public: Trial() {
6
2058
by: Pallav singh | last post by:
Hi All How Does compiler implement virtual destructor ??? as we all know if base class destructor is virtual..........then while wriiting statemnt like this Base * b = new Derived( ); delete b;
0
8737
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8649
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9232
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
1
8978
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
1
6573
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5905
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4411
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4665
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2399
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.