By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,851 Members | 2,104 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,851 IT Pros & Developers. It's quick & easy.

More effective C++

P: n/a
I was just going through this book by Scott Meyers and did not fully
follow item 10.
Basically he says the constructor should catch all exceptions, do any
cleanups necessary and then throw. This is because otherwise the member
objects already created can not be destroyed from outside since the
container object itself is not fully created.

Look at this - (myclass contains objects of class1 and class2)
Class myclass {
class1 m_class1;
class2 m_class2;
public:
myclass(int c1, int c2):m_class1(c1), m_class2(c2) {}
}

Assume both class1 and class2 have constructors which take int
parameters.
so m_class1 gets initialized first and then m_class2. If the contructor
of class2 throws an exception, even after its own cleanup, how would it
help? m_class1 is already contructed. How is it destroyed?

I actually tried this on VC++ 6 compiler and it seems to work. As in ,
m_class1's destructor indeed gets called! I think class1 and class2
initializations are independently happening and we can not cleanup one
because of an exception in the other.

Please let me know if I am missing something here. How does the
compiled code know that m_class1 is contructed and it needs to be
destroyed whereas it passes the exception from m_class2 as is.

Jun 15 '06 #1
Share this Question
Share on Google+
15 Replies


P: n/a
vi************@yahoo.com wrote:

Assume both class1 and class2 have constructors which take int
parameters.
so m_class1 gets initialized first and then m_class2. If the contructor
of class2 throws an exception, even after its own cleanup, how would it
help? m_class1 is already contructed. How is it destroyed?


The compiler generates code that destroys it. The cleanup you need to do
in response to an exception in a constructor is for things that don't
have appropriate destructors.

--

Pete Becker
Roundhouse Consulting, Ltd.
Jun 15 '06 #2

P: n/a
> The cleanup you need to do
in response to an exception in a constructor is for things that don't
have appropriate destructors.


Thanks for the response. But I will have to disagree a bit. Infact in
the example he has given in the book the cleanup code has
delete theImage;
etc where theImage is an object with a welldefined dtor.

--Vikram

Jun 15 '06 #3

P: n/a
> The cleanup you need to do
in response to an exception in a constructor is for things that don't
have appropriate destructors.


Thanks for the response. But I will have to disagree a bit. Infact in
the example he has given in the book the cleanup code has
delete theImage;
etc where theImage is an object with a welldefined dtor.

--Vikram

Jun 15 '06 #4

P: n/a
vi************@yahoo.com schrieb:
The cleanup you need to do
in response to an exception in a constructor is for things that don't
have appropriate destructors.
Thanks for the response. But I will have to disagree a bit. Infact in
the example he has given in the book the cleanup code has
delete theImage;
etc where theImage is an object with a welldefined dtor.


The example in the book dynamically allocates memory with "new". The
code snippet you have posted doesn't. Note the difference.
Therefore, you need to delete theImage explicitly (at this point, the
dtor of theImage will be called). When using new, you have the
responsibility clear the memory on your own (but you could use something
as boost::shared_ptr and give the responsibility of deletion to this
class).
--Vikram


hth,
Gernot
Jun 15 '06 #5

P: n/a
In message <11**********************@r2g2000cwb.googlegroups. com>,
vi************@yahoo.com writes
The cleanup you need to do
in response to an exception in a constructor is for things that don't
have appropriate destructors.


Thanks for the response. But I will have to disagree a bit. Infact in
the example he has given in the book the cleanup code has
delete theImage;
etc where theImage is an object with a welldefined dtor.


Nope. theImage is a *pointer* to such an object. Pointers don't have
destructors, so _you_ have to arrange that the object it points to gets
destroyed, by calling delete.
--
Richard Herring
Jun 15 '06 #6

P: n/a
> The example in the book dynamically allocates memory with "new". The
code snippet you have posted doesn't. Note the difference.
Therefore, you need to delete theImage explicitly (at this point, the
dtor of theImage will be called). When using new, you have the
responsibility clear the memory on your own (but you could use something
as boost::shared_ptr and give the responsibility of deletion to this
class).


Thanks Gernot. Yes, you are right about the example in the book. I was
trying to demonstrate my confusion using objects rather than pointers
because the book specifically says pointers better have a try/catch
blocks for initializations, either in constructor or in a private
member function. Please have a look at the initImage/initAudioImage
methods on page 73 (atleast for the version of the book I have).

In short, I am fine with all the examples that the book has. But I had
a question regarding the whole concept when we have member
initialization lists. How does the code know that m_class1 is already
constructed and should be destroyed? The destructor of the container
object does not get called since it has thrown an exception. So how it
figure out the member objects that are fully created?

Thanks,
Vikram

Jun 15 '06 #7

P: n/a

<vi************@yahoo.com> wrote in message
news:11**********************@p79g2000cwp.googlegr oups.com...
The example in the book dynamically allocates memory with "new". The
code snippet you have posted doesn't. Note the difference.
Therefore, you need to delete theImage explicitly (at this point, the
dtor of theImage will be called). When using new, you have the
responsibility clear the memory on your own (but you could use something
as boost::shared_ptr and give the responsibility of deletion to this
class).


Thanks Gernot. Yes, you are right about the example in the book. I was
trying to demonstrate my confusion using objects rather than pointers
because the book specifically says pointers better have a try/catch
blocks for initializations, either in constructor or in a private
member function. Please have a look at the initImage/initAudioImage
methods on page 73 (atleast for the version of the book I have).

In short, I am fine with all the examples that the book has. But I had
a question regarding the whole concept when we have member
initialization lists. How does the code know that m_class1 is already
constructed and should be destroyed? The destructor of the container
object does not get called since it has thrown an exception. So how it
figure out the member objects that are fully created?


Hi Vikram,

an initialization list is not the same as code in the constructor body.
Those member object initializers you show [:m_class1(c1), m_class2(c2)] are
not normal function calls. They're more like instructions to the compiler
as to _how_ the member objects should be initialized at construction time.
So the normal rules still apply for construction and destruction (and thus
the automatic calling of contructors and destructors).

During construction, the members are constructed for you, in the order
they are declared in the class (which need not be the same as the order of
your initialization list, by the way). When the class is destroyed, the
members are deconstructed in reverse order, and then the class object itself
is destroyed. So all destructors get called automatically.

It's only when you do dynamic allocations in your constructor (e.g.,
using new) that you need to worry about making sure you call delete in the
event of a failure in the constructor.

-Howard


Jun 15 '06 #8

P: n/a

For me, the most annoying aspects of C++ are:

- It's hard to spell.
- It's not Delphi (or Java, or VB).
- There's always that terrible nagging fear that, should I invoke Undefined
Behavior (TM), my hard drive might catch fire, my email system send nasty
messages to my boss, or I could accidently launch a Titan III missile at
China, starting World War 3.

Oh yeah, there's that annoying part about getting paid too much, too...

-Howard
Jun 15 '06 #9

P: n/a

"Howard" <al*****@hotmail.com> wrote in message news:6xfkg.28520

oops, wrong thread... <Cancel!><Cancel!!><Cancel!!!>...arrgh!

(Now ask me about the most annoying things about Outlook Express...)
Jun 15 '06 #10

P: n/a
Howard wrote:
"Howard" <al*****@hotmail.com> wrote in message news:6xfkg.28520

oops, wrong thread... <Cancel!><Cancel!!><Cancel!!!>...arrgh!

(Now ask me about the most annoying things about Outlook Express...)


LOL... THE Most annoying thing about comp.lang.c++:
- All that whining about what's the most annoying thing in C++.
The second most annoying thing about comp.lang.c++:
- All those "questions" whether the asker should learn C++ or Java.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 15 '06 #11

P: n/a
> an initialization list is not the same as code in the constructor body.
Those member object initializers you show [:m_class1(c1), m_class2(c2)] are
not normal function calls. They're more like instructions to the compiler
as to _how_ the member objects should be initialized at construction time.
So the normal rules still apply for construction and destruction (and thus
the automatic calling of contructors and destructors).

During construction, the members are constructed for you, in the order
they are declared in the class (which need not be the same as the order of
your initialization list, by the way). When the class is destroyed, the
members are deconstructed in reverse order, and then the class object itself
is destroyed. So all destructors get called automatically.

It's only when you do dynamic allocations in your constructor (e.g.,
using new) that you need to worry about making sure you call delete in the
event of a failure in the constructor.


Hi Howard, I understand all of the above except for the line
"When the class is destroyed, the members are deconstructed in reverse
order, and then the class object itself is destroyed. So all
destructors get called automatically."
The problem here is the main container class (myClass in my example) is
never destroyed. If the main destructor was being called, I fully
understand how the contained objects' destructors would be called.

Anyway, looks like I am making it more complicated than what it is. Let
me think for a while and if I still dont follow, I will get back with a
better example and specific questions.

Thanks to all who replied.
--Vikram

Jun 16 '06 #12

P: n/a
> Hi Howard, I understand all of the above except for the line
"When the class is destroyed, the members are deconstructed in reverse
order, and then the class object itself is destroyed. So all
destructors get called automatically."
The problem here is the main container class (myClass in my example) is
never destroyed. If the main destructor was being called, I fully
understand how the contained objects' destructors would be called.

Anyway, looks like I am making it more complicated than what it is. Let
me think for a while and if I still dont follow, I will get back with a
better example and specific questions.

Thanks to all who replied.
--Vikram


The reason the "main container class" is never destroyed is because
it's never constructed (fully). If the destructor was called you
wouldn't know which part of the object was constructed (and should be
destroyed) and which parts was not constructed and therefore shouldn't
be destroyed. The only place where you (or the compiler) knows which
parts of the object has been constructed is in the constructor.

There is actually two cases here:

1. An exception is thrown in the construction of any of the possible
base objects (class A : public Base { /* ... */ }; ) or any of the
member objects (either specified in the initialization list or just
default constructed if not part of the list). In this case the compiler
knows what to do and calls the destructor of all objects contructed so
far in reverse order. And the contructor body of your class i never
called. This means any contruction that should have taken place there
is not performed and therefore you don't need to call the destructor.

2. If all base and member objects are contructed ok, the contructor
body of your class is reached. In this case you have to be careful
since if you make any resource allocations (like memory with new) and
something makes your contructor throw later in the construcotr, your
destructor is *not* called since the object is not fully contructed.
You therefore have to guard the contructor code with try/catch (or use
RAII objects like smart pointers - auto_ptr or boost::shared_ptr which
are automaticall destroyed) and destroy any objects allocated so far
manually with delete or similar.

/ Phl

Jun 16 '06 #13

P: n/a
On 2006-06-15, vi************@yahoo.com <vi************@yahoo.com> wrote:
The example in the book dynamically allocates memory with "new". The
code snippet you have posted doesn't. Note the difference.
Therefore, you need to delete theImage explicitly (at this point, the
dtor of theImage will be called). When using new, you have the
responsibility clear the memory on your own (but you could use something
as boost::shared_ptr and give the responsibility of deletion to this
class).

[snip]
In short, I am fine with all the examples that the book has. But I had
a question regarding the whole concept when we have member
initialization lists. How does the code know that m_class1 is already
constructed and should be destroyed? The destructor of the container
object does not get called since it has thrown an exception. So how it
figure out the member objects that are fully created?
The compiler has the responsibility to figure this out and to destroy the
objects that it has created for you. It allocates memory for your members and
constructs them either by using a constructor without parameters or a
specialized one if you have stated one or more arguments in the initialization
list. When the object's lifetime is over, it destroys these member objects.

When an object cannot be build due to an exception, the desctructor will not
be called, as you mention correctly. This is due to the fact that the object
never was really "alive". In this case, the compiler will destruct members
that were successfully created by the compiler when the constructor is
left due to an exception.
Thanks,
Vikram


Regards,
Gerno
Jun 17 '06 #14

P: n/a
On 2006-06-15, vi************@yahoo.com <vi************@yahoo.com> wrote:
The example in the book dynamically allocates memory with "new". The
code snippet you have posted doesn't. Note the difference.
Therefore, you need to delete theImage explicitly (at this point, the
dtor of theImage will be called). When using new, you have the
responsibility clear the memory on your own (but you could use something
as boost::shared_ptr and give the responsibility of deletion to this
class).

[snip]
In short, I am fine with all the examples that the book has. But I had
a question regarding the whole concept when we have member
initialization lists. How does the code know that m_class1 is already
constructed and should be destroyed? The destructor of the container
object does not get called since it has thrown an exception. So how it
figure out the member objects that are fully created?
The compiler has the responsibility to figure this out and to destroy the
objects that it has created for you. It allocates memory for your members and
constructs them either by using a constructor without parameters or a
specialized one if you have stated one or more arguments in the initialization
list. When the object's lifetime is over, it destroys these member objects.

When an object cannot be build due to an exception, the desctructor will not
be called, as you mention correctly. This is due to the fact that the object
never was really "alive". In this case, the compiler will destruct members
that were successfully created by the compiler when the constructor is
left due to an exception.
Thanks,
Vikram


Regards,
Gerno
Jun 17 '06 #15

P: n/a
On 2006-06-15, vi************@yahoo.com <vi************@yahoo.com> wrote:
The example in the book dynamically allocates memory with "new". The
code snippet you have posted doesn't. Note the difference.
Therefore, you need to delete theImage explicitly (at this point, the
dtor of theImage will be called). When using new, you have the
responsibility clear the memory on your own (but you could use something
as boost::shared_ptr and give the responsibility of deletion to this
class).

[snip]
In short, I am fine with all the examples that the book has. But I had
a question regarding the whole concept when we have member
initialization lists. How does the code know that m_class1 is already
constructed and should be destroyed? The destructor of the container
object does not get called since it has thrown an exception. So how it
figure out the member objects that are fully created?
The compiler has the responsibility to figure this out and to destroy the
objects that it has created for you. It allocates memory for your members and
constructs them either by using a constructor without parameters or a
specialized one if you have stated one or more arguments in the initialization
list. When the object's lifetime is over, it destroys these member objects.

When an object cannot be build due to an exception, the desctructor will not
be called, as you mention correctly. This is due to the fact that the object
never was really "alive". In this case, the compiler will destruct members
that were successfully created by the compiler when the constructor is
left due to an exception.
Thanks,
Vikram


Regards,
Gernot
Jun 17 '06 #16

This discussion thread is closed

Replies have been disabled for this discussion.