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 14 3121
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 :)
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
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
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
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.
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
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.
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
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
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.
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.
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
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
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 This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
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...
|
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...
|
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
|
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...
|
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...
|
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...
|
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...
|
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 ?
|
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?
|
by: isladogs |
last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM)
The start time is equivalent to 19:00 (7PM) in Central...
|
by: erikbower65 |
last post by:
Using CodiumAI's pr-agent is simple and powerful. Follow these steps:
1. Install CodiumAI CLI: Ensure Node.js is installed, then run 'npm install -g codiumai' in the terminal.
2. Connect to...
|
by: linyimin |
last post by:
Spring Startup Analyzer generates an interactive Spring application startup report that lets you understand what contributes to the application startup time and helps to optimize it. Support for...
|
by: Rina0 |
last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
|
by: DJRhino |
last post by:
Private Sub CboDrawingID_BeforeUpdate(Cancel As Integer)
If = 310029923 Or 310030138 Or 310030152 Or 310030346 Or 310030348 Or _
310030356 Or 310030359 Or 310030362 Or...
|
by: lllomh |
last post by:
Define the method first
this.state = {
buttonBackgroundColor: 'green',
isBlinking: false, // A new status is added to identify whether the button is blinking or not
}
autoStart=()=>{
|
by: lllomh |
last post by:
How does React native implement an English player?
|
by: Mushico |
last post by:
How to calculate date of retirement from date of birth
|
by: DJRhino |
last post by:
Was curious if anyone else was having this same issue or not....
I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...
| |