473,320 Members | 1,535 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Member destructor inside a constructor

Suppose there's a class A. There's another class called B which looks
like this:

class B {
private:
A a;
public :
B() { a.~A() }
}

Notice that B has a member 'a' which is an instance of class A. Also
notice that the default constructor of B calls the destructor of 'a'.

Let's now use class B in a main() block:

void main() {
B obj;
}

My question is: when this main() is run, what happens?

Well, I myself have compiled and run this code and I found that the
destructor of 'a' is called twice: first when 'obj' is constructed
(because class B's constructor calls 'a's destructor explicitly) and
second time when the control exits the main() block and 'obj' is
destroyed by calling class B's destructor.

Now if 'a' has already been destroyed in class B's constructor, how can
'a''s destructor be called again through class B's destructor? Does
that mean that even after 'a's destructor is called in class B's
construtor, it isn't actually destroyed?

My motive for this experiment is to know what to do when you want to
throw exceptions from a constructor of any class and you want to
properly destroy all its member objects before the exception is thrown.
Is calling members' destructors like I did above a right way to achieve
this?

Thanks in advance,
Gurry

Mar 21 '06 #1
14 3171
Well, if destructor of A class does nothing with freeing objects, then
it's just calling any other method.
So if destructor of A is empty, then it doesn't do anything, and a is
destroyed when class B is destroyed.

I guess :)

Mar 21 '06 #2

gurry wrote:
Suppose there's a class A. There's another class called B which looks
like this:

class B {
private:
A a;
public :
B() { a.~A() }
}

Notice that B has a member 'a' which is an instance of class A. Also
notice that the default constructor of B calls the destructor of 'a'.

Let's now use class B in a main() block:

void main() {
B obj;
}

My question is: when this main() is run, what happens?


I happens the following:
B::B()
A::A()
A::~() // your explicit call
B::~B() // called automatically, since the scope of obj ended
A::~A() // called by the generated destructor of class B

When an exception is thrown from the constructor, you should take care
of deallocating the resources (e.g. memory) you allocated at
construction time, before throwing the exception, because no destructor
of the class will be called (because the object is considered as
constructed only after the complete execution of the constructor).

Catalin

Mar 21 '06 #3

gurry wrote:
Suppose there's a class A. There's another class called B which looks
like this:

class B {
private:
A a;
public :
B() { a.~A() }
}

Notice that B has a member 'a' which is an instance of class A. Also
notice that the default constructor of B calls the destructor of 'a'.

Let's now use class B in a main() block:

void main() {
B obj;
}

My question is: when this main() is run, what happens?


The compiler barfs on void, I guess. It's int main() { }
After that, the program will have Undefined Behavior when B::~B() is
called. The destructor always destroys every member, which isn't
possible here. Anything may happen at that point.

HTH,
Michiel Salters

Mar 21 '06 #4
gurry wrote:
Suppose there's a class A. There's another class called B which looks
like this:

class B {
private:
A a;
public :
B() { a.~A() }
}

Notice that B has a member 'a' which is an instance of class A. Also
notice that the default constructor of B calls the destructor of 'a'.

Let's now use class B in a main() block:

void main() {
B obj;
}

My question is: when this main() is run, what happens?
That would cause the program to call A::~A on a destroyed object, which
is Undefined Behavior I believe. Don't do it.

Well, I myself have compiled and run this code and I found that the
destructor of 'a' is called twice: first when 'obj' is constructed
(because class B's constructor calls 'a's destructor explicitly) and
second time when the control exits the main() block and 'obj' is
destroyed by calling class B's destructor.
Good! Exactly what should happen! But you are also lucky (or unlucky)
that the program didn't crash.

Now if 'a' has already been destroyed in class B's constructor, how can
'a''s destructor be called again through class B's destructor? Does
that mean that even after 'a's destructor is called in class B's
construtor, it isn't actually destroyed?
The member is indeed destroyed in B's constructor. But the compile would
have no clue whether the member is destroyed or not--it won't bother to
fathom your call to the destructor.

All members are automatically destroyed upon destruction of their
parent. If any of them has a non-trivial destructor it will be called.
Simple as that.

My motive for this experiment is to know what to do when you want to
throw exceptions from a constructor of any class and you want to
properly destroy all its member objects before the exception is thrown.
Is calling members' destructors like I did above a right way to achieve
this?
You can't test it, just as you can't predict the future. Calling the
destructor before hand you won't give you the answer. Consider:

// Flawed example
class not_so_nice
{
public:
~not_so_nice()
{
bool n;
cin >> n;
if (n) throw n;
}
};

class cynic
{
not_so_nice nsn;
public:
cynic()
{
nsn.~not_so_nice(); // test destructor
new(&nsn) not_so_nice; // reconstruct member
}
};

int main()
{
cynic c;
}// oops, can still throw from destructor

Since you can't predict the user input you can't test the behavior of
~not_so_nice.

Generally, destructors don't throw. It is not worth protecting from
extreme cases.

On the other hand, if you are required to be absolutely exception proof
for destruction, you can mandate the member to provide no throw function
for destruction, for example:

class safe_selfdestructor
{
public:
virtual void destroy_self(void) throw() = 0;
};

class example: public safe_selfdestructor
{
public:
void destroy_self(void) throw(){delete this;}

~example()
try
{
// ...
}
catch (...){} // hide exception
};

class cynic
{
example* p_ex;
safe_selfdestructor* p_des;
public:
cynic(){p_ex = new example; p_des = p_ex;}
~cynic(){p_des->destroy_self();}
};

Beware that trying to hide a thrown exception can be more dangerous then
letting it crash your program. You have been warned.


Thanks in advance,
Gurry


Regards,
Ben
Mar 21 '06 #5
gurry <fr****************@gmail.com> wrote:
class B {
private:
A a;
public :
B() { a.~A() }
}


that's an undefined behaviour. Unfortunatelly, in most situations you
will not see a crash
B.

Mar 21 '06 #6
Thank you all guys. This clears up things a bit.

And benben thanks for the detailed post but I guess you read me wrong.
I intend to throw an exception from a constructor not a destructor
(which I think is more often the case, though I'm not sure).

So the question remains: how do you gracefully destroy member objects
already created by the constructor before you throw an exception. In my
post, I tried explict calls to the destructors of the already created
member objects, which, as it is confirmed by you guys, is not a good
practice. Then how do you achieve the graceful destruction of member
objects?

I read one way to do it in the Bruce Eckel book that involved having
pointers to objects as members instead of the objects themselves. But
pointers are not always possible to have. What if I am required to have
a vector of some, say, userdefined class objects as a member of my
class? How would I make sure that this vector's destructor is called
before throwing an exception?

Thanks in advance.
gurry

Mar 22 '06 #7
gurry wrote:
Thank you all guys. This clears up things a bit.

And benben thanks for the detailed post but I guess you read me wrong.
I intend to throw an exception from a constructor not a destructor
(which I think is more often the case, though I'm not sure).

So the question remains: how do you gracefully destroy member objects
already created by the constructor before you throw an exception. In my


Just don't. The compiler will do it automagically.

Mar 22 '06 #8
First of all , the call a::~A() does not destroy the object a. it is
merely a function call. Only the constructor cannot be called
explicitly in a C++ program. Generally, the intent of calling the
destructor explicitly is to cleanup and reuse the object. The
destructor is call twice because it was called once explicitly and
then automatically by the compiler as the destruction sequence of B.

far as i know the behaviour is NOT undefined. check out the ISO
standard.
My motive for this experiment is to know what to do when you want to
throw exceptions from a constructor of any class and you want to
properly destroy all its member objects before the exception is thrown.
Is calling members' destructors like I did above a right way to achieve this?


it is guranteed by the C++ standard, far as i know, that inside a
constructor, any member object created "Completely" in the stack will
destroyed if the constructor throws. For dynamically created objects
(with new) you have to take cate of that. If you face something like
this, consider using auto pointer (std::auto_ptr<>) or use a two stage
construction (i.e. constructor does nothing and a function like
initialize() does the logical construction of the object).

I hope it was of some help

cheers
Iftekhar

Mar 24 '06 #9
iftekhar wrote:
First of all , the call a::~A() does not destroy the object a. it is
merely a function call.
Nope: the call to the destructor ends the lifetime of the object [3.8/4].
All subsequent operations on the object are undefined behavior (including a
second call to the destructor). Well-defined are only operations that refer
to the objects location in memory as raw memory [3.8/5].

Only the constructor cannot be called
explicitly in a C++ program. Generally, the intent of calling the
destructor explicitly is to cleanup and reuse the object.
Nope: "Generally", you don't call the destructor explicitly. Specifically,
if you do so, then you are very likely writing an allocator class and your
explicit destructor calls match some calls to placement new (the standards
hook to construct an object at a given location in memory -- as close to an
explicit constructor call as you can get).

In other words: you cannot reuse the object (because it's dead). You can,
however, reuse the memory occupied by the objects dead body. To accomplish
this, you can construct a new object in the same place by calling placement
new.

The destructor is call twice because it was called once explicitly and
then automatically by the compiler as the destruction sequence of B.

far as i know the behaviour is NOT undefined.
Nope: it is undefined [12.4/14].

check out the ISO standard.


Good advice!
[snip]
Best

Kai-Uwe Bux
Mar 24 '06 #10
iftekhar wrote:
....
it is guranteed by the C++ standard, far as i know, that inside a
constructor, any member object created "Completely" in the stack will
destroyed if the constructor throws. For dynamically created objects
(with new) you have to take cate of that.


Nope. If the *constructor* throws, it is guaranteed that any sub-object
that was completely constructed is destructed and that the deallocator
function is called to free up the memory that was allocated. If the
deallocator function exists, of course.

Mar 24 '06 #11
Thanks a lot guys. Now I know: if my class holds a 'sub-object' then
its destructor will surely be called when my class's constructor throws
exception, but if my class has a *pointer* to a 'sub-object', then
that's my own responsibility to clean up.

Thanks for the discussion.

Mar 25 '06 #12
Hi,
Thanks a lot. I completely forgot about the placement new that should
(must??) be used with the explicit destructor calls. Thanks again for
the refresh :D.
cheers
Iftekhar

Mar 27 '06 #13
AnalogFile wrote:
Nope. If the *constructor* throws, it is guaranteed that any sub-object
that was completely constructed is destructed
That is exactly what i ment.
and that the deallocator
function is called to free up the memory that was allocated. If the
deallocator function exists, of course.


far as i know, the deallocator (assuming destructor) will not be called
since the object creation was not "complete"ed. The base class
destructors will be called though (if they were created completely).
fro this reason there is somthing called "function-try-block".
class foo
{
private:
char* p;
char* q;
public:
foo (void)
try
{ : p(new char[100]),
q(new char[100])
{
...
}
}
catch(bad_alloc ??)
{
delete p;
delete q;
}
}
even that does not help here, since you cant tell whether the p or q
allocation failed.

correct me if i am wrong.

cheers
iftekhar

Mar 27 '06 #14
gurry wrote:
[snip]
My motive for this experiment is to know what to do when you want to
throw exceptions from a constructor of any class and you want to
properly destroy all its member objects before the exception is thrown.
Is calling members' destructors like I did above a right way to achieve
this?


When exceptions are thrown the stack gets unwound till the
exception is caught. So, if each class has appropriate things
to give back resources in its dtor, you don't want to be
explicitly calling dtors. That is, any problems you could
theoretically have avoided by explicitly calling a dtor would
automatically be avoided by stack unwinding. And any
probs that you would get into through stack unwinding
would be made no better by explicitly calling the dtor.

So, for example: Suppose you run out of memory, and then
the stack unwinding fails because of that. I don't know,
maybe a dtor needs a temp variable to run properly, and
does not have room to make it, so the dtor fails. Now you
have big trouble in code land. But explicitly calling the
dtor does not make this any bette, in fact it could be
worse.

So, explicitly calling a dtor is usually a bad idea.
Socks

Mar 27 '06 #15

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

Similar topics

22
by: Ruben Van Havermaet | last post by:
Hi, I have a problem using member functions in derived classes that override virtual member functions of base classes. The following pieces of (simplified) code don't work. Can anybody give...
6
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...
2
by: Gabrielle A. Grün | last post by:
Hi All, Does anyone know a way around the illegal reference of a non-static member? Thanks. iNHERITANCE HIERACY
4
by: Josefo | last post by:
Hello, is someone so kind to tell me why I am getting the following errors ? vector_static_function.c:20: error: expected constructor, destructor, or type conversion before '.' token...
6
by: VSP | last post by:
Hello, I am just implementing singleton pattern in various ways. In one implementation I created a static member and returning that static member in the getInstance() function. I have made...
1
by: newbie | last post by:
This is a snippet from C++ FAQs, which I have never done--- when I do such a thing, I would declare function used by constructor ( in this example, init() ) as static. But I do understand that it...
10
by: JosephLee | last post by:
In Inside C++ object Model, Lippman said there are four cases in which compile will sythesize a default constructor to initialize the member variables if the constructor is absent: 1. there is a...
5
by: wiskey5alpha | last post by:
Hello all. I have a design question. assuming we have class Bar {...} // body omitted for clarity class Foo { // should Bar be implemented as a pointer or not here ?
15
by: akomiakov | last post by:
Is there a technical reason why one can't initialize a cost static non- integral data member in a class?
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

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.