Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > c++ question regarding exception safety

Reply
Thread Tools

c++ question regarding exception safety

 
 
unix.sh@gmail.com
Guest
Posts: n/a
 
      03-06-2008
In Section E.3.5. of the book 'the c++ programming language 3rd
edtion' by Bjarne Stroustrup, why it needs to add the check: 'if (v)'
in the vector_base destrctor of the vector_base implmentation.

In my understanding, if this statement failed(v=alloc.allocate(n)) in
the contrstructor, the destrctor will never be called. So no check
needed in the destructor.

But according to the book, Bjarned says clearly in the book(p. 950,
Section E.3.5)

Note that this attempt to write safer code complicates the invariant
for the class: It is no longer
guaranteed that v points to allocated memory. Now v might be 0 .

I am confused now.

Thanks for your help,

Michael
 
Reply With Quote
 
 
 
 
Alf P. Steinbach
Guest
Posts: n/a
 
      03-06-2008
* :
> In Section E.3.5. of the book 'the c++ programming language 3rd
> edtion' by Bjarne Stroustrup, why it needs to add the check: 'if (v)'
> in the vector_base destrctor of the vector_base implmentation.
>
> In my understanding, if this statement failed(v=alloc.allocate(n)) in
> the contrstructor, the destrctor will never be called. So no check
> needed in the destructor.
>
> But according to the book, Bjarned says clearly in the book(p. 950,
> Section E.3.5)
>
> Note that this attempt to write safer code complicates the invariant
> for the class: It is no longer
> guaranteed that v points to allocated memory. Now v might be 0 .
>
> I am confused now.


As I recall, the point was that alloc.allocate(n) does /not/ throw an exception,
that that constructor does not signal failure by way of an exception but instead
notes in the object state (e.g. by having a null-pointer value somewhere) that
it has failed to initialize.

As Bjarne notes, that complicates the class invariant: it essentially introduces
a meta-level class invariant, "object has been initialized OR (real class
invariant)".

That's known as a zombie object, and they're a common problem in
garbage-collection based languages like Java and C# that do not have automated
deterministic destruction. Mostly this problem manifests as complicated
implementation code (peppered with checks for validity), equally complicated
client code (peppered with manual cleanup calls).


Cheers, & hth.,

- Alf


--
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?
 
Reply With Quote
 
 
 
 
unix.sh@gmail.com
Guest
Posts: n/a
 
      03-06-2008
On Mar 6, 12:33*pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * unix...@gmail.com:
>
>
>
>
>
> > In Section E.3.5. of the book 'the c++ programming language 3rd
> > edtion' by Bjarne Stroustrup, why it needs to add the check: 'if (v)'
> > in the vector_base destrctor of the vector_base implmentation.

>
> > In my understanding, if this statement failed(v=alloc.allocate(n)) in
> > the contrstructor, the destrctor will never be called. So no check
> > needed in the destructor.

>
> > But according to the book, Bjarned says clearly in the book(p. 950,
> > Section E.3.5)

>
> > Note that this attempt to write safer code complicates the invariant
> > for the class: It is no longer
> > guaranteed that v points to allocated memory. Now v might be 0 .

>
> > I am confused now.

>
> As I recall, the point was that alloc.allocate(n) does /not/ throw an exception,
> that that constructor does not signal failure by way of an exception but instead
> notes in the object state (e.g. by having a null-pointer value somewhere) that
> it has failed to initialize.
>
> As Bjarne notes, that complicates the class invariant: it essentially introduces
> a meta-level class invariant, "object has been initialized OR (real class
> invariant)".
>
> That's known as a zombie object, and they're a common problem in
> garbage-collection based languages like Java and C# that do not have automated
> deterministic destruction. *Mostly this problem manifests as complicated
> implementation code (peppered with checks for validity), equally complicated
> client code (peppered with manual cleanup calls).
>
> Cheers, & hth.,
>
> - Alf
>
> --
> 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?- Hide quoted text -
>
> - Show quoted text -


Thanks a lot for your information.

I understand the ponit Bjarne tries to express. But my question again
is what's the difference between the explicit assignment
v=alloc.allocate(n) and v(alloc.allocate(n)), the later
initiailization style is being used in the implementation in Section E.
3.2.(p. 943). According to the book, the later
one( v(alloc.alocate(n)) in the initializer list) is better than
v=alloc.allocate(n) in the constructor. In my understanding if
alloc.allocate(n) doesn't throw exception, v is still a dangling
pointer, which is the same as v=0. So both of them are the same.

Thanks,
Michael

 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      03-06-2008
* :
> On Mar 6, 12:33 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>> * unix...@gmail.com:
>>
>>
>>
>>
>>
>>> In Section E.3.5. of the book 'the c++ programming language 3rd
>>> edtion' by Bjarne Stroustrup, why it needs to add the check: 'if (v)'
>>> in the vector_base destrctor of the vector_base implmentation.
>>> In my understanding, if this statement failed(v=alloc.allocate(n)) in
>>> the contrstructor, the destrctor will never be called. So no check
>>> needed in the destructor.
>>> But according to the book, Bjarned says clearly in the book(p. 950,
>>> Section E.3.5)
>>> Note that this attempt to write safer code complicates the invariant
>>> for the class: It is no longer
>>> guaranteed that v points to allocated memory. Now v might be 0 .
>>> I am confused now.

>> As I recall, the point was that alloc.allocate(n) does /not/ throw an exception,
>> that that constructor does not signal failure by way of an exception but instead
>> notes in the object state (e.g. by having a null-pointer value somewhere) that
>> it has failed to initialize.
>>
>> As Bjarne notes, that complicates the class invariant: it essentially introduces
>> a meta-level class invariant, "object has been initialized OR (real class
>> invariant)".
>>
>> That's known as a zombie object, and they're a common problem in
>> garbage-collection based languages like Java and C# that do not have automated
>> deterministic destruction. Mostly this problem manifests as complicated
>> implementation code (peppered with checks for validity), equally complicated
>> client code (peppered with manual cleanup calls).
>>
>> Cheers, & hth.,
>>
>> - Alf
>>
>> --
>> 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?- Hide quoted text -
>>
>> - Show quoted text -

>
> Thanks a lot for your information.
>
> I understand the ponit Bjarne tries to express. But my question again
> is what's the difference between the explicit assignment
> v=alloc.allocate(n) and v(alloc.allocate(n)), the later
> initiailization style is being used in the implementation in Section E.
> 3.2.(p. 943). According to the book, the later
> one( v(alloc.alocate(n)) in the initializer list) is better than
> v=alloc.allocate(n) in the constructor. In my understanding if
> alloc.allocate(n) doesn't throw exception, v is still a dangling
> pointer, which is the same as v=0. So both of them are the same.
>
> Thanks,
> Michael
>


Please don't quote signatures.

--
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?
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-07-2008
On Mar 6, 6:33 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> * unix...@gmail.com:


[...]
> That's known as a zombie object, and they're a common problem
> in garbage-collection based languages like Java and C# that do
> not have automated deterministic destruction.


You've got me there. How does the lack of automated
deterministic destruction relate to zombie objects. I would
have thought that zombie objects occured because of the lack of
exceptions. (Anything you can do with a destructor in C++, you
can do with a try block in Java. In client code, of course,
the try block is usually a lot more painful, but in a
constructor, I don't think it makes as much difference. And of
course, there's no relationship between "garbage collection
based" and "do not have automated deterministic destruction":
the current proposals are for C++ to have both, and of course,
there are an awful lot of older languages out there that have
neither.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-07-2008
On Mar 6, 7:05 pm, unix...@gmail.com wrote:
> On Mar 6, 12:33 pm, "Alf P. Steinbach" <al...@start.no> wrote:


[...]
> I understand the ponit Bjarne tries to express. But my
> question again is what's the difference between the explicit
> assignment v=alloc.allocate(n) and v(alloc.allocate(n)), the
> later initiailization style is being used in the
> implementation in Section E. 3.2.(p. 943). According to the
> book, the later one( v(alloc.alocate(n)) in the initializer
> list) is better than v=alloc.allocate(n) in the constructor.
> In my understanding if alloc.allocate(n) doesn't throw
> exception, v is still a dangling pointer, which is the same as
> v=0. So both of them are the same.


It depends more on the type than on explicit initialization or
not. The point is that once v has been constructed, its
destructor will be called if the constructor of the containing
class exits via an exception. If v is a non-class type (e.g. a
raw pointer), the destructor is a no-op, and nothing happens.
If v is a class type, it could do some clean-up.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      03-07-2008
* James Kanze:
> On Mar 6, 6:33 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>> * unix...@gmail.com:

>
> [...]
>> That's known as a zombie object, and they're a common problem
>> in garbage-collection based languages like Java and C# that do
>> not have automated deterministic destruction.

>
> You've got me there. How does the lack of automated
> deterministic destruction relate to zombie objects.


You have known that earlier...

When you don't have automatic deterministic destruction, and you have some
resource to release, you have to implement some kind of manual cleanup, e.g. a
member function destroy() available to client code.

There's no way to guarantee that destroy() is called exactly once or only when
the object will no longer be used. Worse, to support code that forgets to call
destroy(), it's not uncommon to also do cleanup in a finalize() function that
may be called by the garbage collection. And a common solution is to let the
cleanup code note in the object's state that it's destroyed, a zombie.

An example of this monstrosity (googled this up now just for your convenience):
<url: http://www.javapractices.com/topic/TopicAction.do?Id=43>.

Problem with that example: abstracting a resource that can become invalid on its
own, such as a file or db connection, is inherently difficult, so that the
complexity in that zombie solution doesn't quite properly illustrate the evils
of zombies. So think about e.g. a window handle instead of a db handle. With
RAII, however, the checking of zombieness can be automated and centralized by a
smart pointer instead of having zombie checks peppered throughout the code.


Cheers, & hth.,

- Alf

--
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?
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-07-2008
On 7 mar, 17:43, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:


> > On Mar 6, 6:33 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> >> * unix...@gmail.com:


> > [...]
> >> That's known as a zombie object, and they're a common problem
> >> in garbage-collection based languages like Java and C# that do
> >> not have automated deterministic destruction.


> > You've got me there. How does the lack of automated
> > deterministic destruction relate to zombie objects.


> You have known that earlier...


> When you don't have automatic deterministic destruction, and
> you have some resource to release, you have to implement some
> kind of manual cleanup, e.g. a member function destroy()
> available to client code.


I think we're talking about a different context. I don't see
the relevance with regards to constructors or zombie objects
here. (In practice, the destroy() function in C++ is the
destructor. But that's not the issue here.)

> There's no way to guarantee that destroy() is called exactly
> once or only when the object will no longer be used. Worse, to
> support code that forgets to call destroy(), it's not uncommon
> to also do cleanup in a finalize() function that may be called
> by the garbage collection. And a common solution is to let
> the cleanup code note in the object's state that it's
> destroyed, a zombie.


Now you've lost me completely. I can't make heads or tails out
of the above---it seems to mix any number of separate concepts.

> An example of this monstrosity (googled this up now just for
> your convenience):
> <url:http://www.javapractices.com/topic/TopicAction.do?Id=43>.


> Problem with that example: abstracting a resource that can
> become invalid on its own, such as a file or db connection, is
> inherently difficult, so that the complexity in that zombie
> solution doesn't quite properly illustrate the evils of
> zombies.


OK. We agree there. But my impression is that the problem
being addressed in all this is that Java doesn't have
destructors, so you need a finally block. And as I said, within
the constructor, that's less of a problem than elsewhere,
because it's within the class code itself---it doesn't introduce
a constraint on user code. (Thus, my pre-standard array classes
uses a try block to handle the case where a copy constructor
threw, rather than some special extra class with a destructor.)

Note that in both Java and C++, you can have dangling pointers.
With the difference that you can reliably detect when they are
used in Java (or in C++ with garbage collection). (Except, of
course, I've seen damded little Java code that actually tries to
detect them. Detecting them is the sort of reliability question
that doesn't seem to interest Java programmers.) But that,
again, is more or less separate from the problem of cleaning up
after an error in the constructor.

> So think about e.g. a window handle instead of a db handle.
> With RAII, however, the checking of zombieness can be
> automated and centralized by a smart pointer instead of having
> zombie checks peppered throughout the code.


That is, again, a different issue. Although if I understand
your suggestion correctly, it's an interesting idea---using
normal C++ semantics for destruction, but using smart pointers
for memory management. (I'd buy into it more if smart pointers
could handle cycles easily.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
Alf P. Steinbach
Guest
Posts: n/a
 
      03-07-2008
* James Kanze:
> On 7 mar, 17:43, "Alf P. Steinbach" <al...@start.no> wrote:
>> * James Kanze:

>
>>> On Mar 6, 6:33 pm, "Alf P. Steinbach" <al...@start.no> wrote:
>>>> * unix...@gmail.com:

>
>>> [...]
>>>> That's known as a zombie object, and they're a common problem
>>>> in garbage-collection based languages like Java and C# that do
>>>> not have automated deterministic destruction.

>
>>> You've got me there. How does the lack of automated
>>> deterministic destruction relate to zombie objects.

>
>> You have known that earlier...

>
>> When you don't have automatic deterministic destruction, and
>> you have some resource to release, you have to implement some
>> kind of manual cleanup, e.g. a member function destroy()
>> available to client code.

>
> I think we're talking about a different context. I don't see
> the relevance with regards to constructors or zombie objects
> here.


See below, or earlier in the thread, keeping in mind that a constructor's main
job is (usually) to establish the class invariant.

Or perhaps read Bjarne's article that the OP was referring to.

This all hangs together.


> (In practice, the destroy() function in C++ is the
> destructor. But that's not the issue here.)
>
>> There's no way to guarantee that destroy() is called exactly
>> once or only when the object will no longer be used. Worse, to
>> support code that forgets to call destroy(), it's not uncommon
>> to also do cleanup in a finalize() function that may be called
>> by the garbage collection. And a common solution is to let
>> the cleanup code note in the object's state that it's
>> destroyed, a zombie.

>
> Now you've lost me completely. I can't make heads or tails out
> of the above---it seems to mix any number of separate concepts.


Yes, this all hangs together.


>> An example of this monstrosity (googled this up now just for
>> your convenience):
>> <url:http://www.javapractices.com/topic/TopicAction.do?Id=43>.

>
>> Problem with that example: abstracting a resource that can
>> become invalid on its own, such as a file or db connection, is
>> inherently difficult, so that the complexity in that zombie
>> solution doesn't quite properly illustrate the evils of
>> zombies.

>
> OK. We agree there. But my impression is that the problem
> being addressed in all this is that Java doesn't have
> destructors, so you need a finally block.


That's one problem that can lead to zombies.


Cheers, & hth.,

- Alf

--
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?
 
Reply With Quote
 
James Kanze
Guest
Posts: n/a
 
      03-08-2008
On 7 mar, 22:56, "Alf P. Steinbach" <al...@start.no> wrote:
> * James Kanze:
> > On 7 mar, 17:43, "Alf P. Steinbach" <al...@start.no> wrote:
> >> * James Kanze:


> >>> On Mar 6, 6:33 pm, "Alf P. Steinbach" <al...@start.no> wrote:
> >>>> * unix...@gmail.com:


> >>> [...]
> >>>> That's known as a zombie object, and they're a common problem
> >>>> in garbage-collection based languages like Java and C# that do
> >>>> not have automated deterministic destruction.


> >>> You've got me there. How does the lack of automated
> >>> deterministic destruction relate to zombie objects.


> >> You have known that earlier...


> >> When you don't have automatic deterministic destruction, and
> >> you have some resource to release, you have to implement some
> >> kind of manual cleanup, e.g. a member function destroy()
> >> available to client code.


> > I think we're talking about a different context. I don't see
> > the relevance with regards to constructors or zombie objects
> > here.


> See below, or earlier in the thread, keeping in mind that a
> constructor's main job is (usually) to establish the class
> invariant.


Right. The constructor's. Deterministic destruction and
garbage collection aren't really relevant here: the question is
what happens when for some reason the the constructor cannot
establish the invariants. If the object "exists" anyway (or
perhaps more correctly, in C++ standardese, if there is an
lvalue expression which can refer to it), then you have a
zombie. Zombies can easily be objects with no destructor
(although I suspect that the case is rare in standard C++), and
Zombieism affects local objects (on stack) just like any others;
dynamic allocation is not necessary for zombies to exist.

In older C++, before exceptions were introduced, zombies
couldn't be avoided. If you wrote something like:

{
C obj ;
// ...
}

there was no way to avoid obj "existing". So you had to create
a zombie state, require the client code to check it, verify it
on each access, etc. The key to not having zombies is
exceptions (and you can avoid them just as well in Java as in
C++).

> Or perhaps read Bjarne's article that the OP was referring to.


Bjarne's article didn't really mention zombies. It talked about
cleaning up in the destructor, before (or as a result of)
throwing the exception. If I understood it correctly, Bjarne
didn't consider the possibility of having a zombie; he only
talked about what happens when reporting an error via an
exception.

Again, the problem is common to all languages which have
exceptions. The tools available to solve the problem do vary
from one language to the next---in Java, you must use a try
block; in C++, you have the choice between a try block and a
subobject with a destructor, which will be called once the
subobject has been fully constructed.

Having a choice is, of course, a good thing. But the choice the
programmer makes isn't that critical here---either way, he's
cleaned up. (I'm talking here about explicitly creating a class
which has no other reason d'être but to exploit this behavior of
destructors. Obviously, if the class you are writing is a
client of another, existing class, then that class should take
care of all necessary clean-up in its destructor, and the fact
that you, as a client, don't have to write explicit try/catch
blocks is a definite advantage.)

> This all hangs together.


I still don't see any real relationship. Zombie objects are a
result of design choices (or in pre-exception days, the lack of
a possible choice) concerning the constructor. Deterministic
destruction solves a different set of problems, and garbage
collection is yet a third issue, orthogonal to the other two.

> > (In practice, the destroy() function in C++ is the
> > destructor. But that's not the issue here.)


> >> There's no way to guarantee that destroy() is called exactly
> >> once or only when the object will no longer be used. Worse, to
> >> support code that forgets to call destroy(), it's not uncommon
> >> to also do cleanup in a finalize() function that may be called
> >> by the garbage collection. And a common solution is to let
> >> the cleanup code note in the object's state that it's
> >> destroyed, a zombie.


> > Now you've lost me completely. I can't make heads or tails
> > out of the above---it seems to mix any number of separate
> > concepts.


> Yes, this all hangs together.


How? Before C++ had exceptions, zombie classes were a fact of
life. Even when no dynamic allocation was involved, and in a
few odd cases, when no resources at all were involved.

> >> An example of this monstrosity (googled this up now just for
> >> your convenience):
> >> <url:http://www.javapractices.com/topic/TopicAction.do?Id=43>.


> >> Problem with that example: abstracting a resource that can
> >> become invalid on its own, such as a file or db connection, is
> >> inherently difficult, so that the complexity in that zombie
> >> solution doesn't quite properly illustrate the evils of
> >> zombies.


> > OK. We agree there. But my impression is that the problem
> > being addressed in all this is that Java doesn't have
> > destructors, so you need a finally block.


> That's one problem that can lead to zombies.


How? This is one case where Java and C++ behave almost
identically:

{
MyClass obj = new MyClass ;
// ...
}

in Java behaves exactly like:

{
MyClass obj ;
// ...
}

in C++. If the constructor exits via an exception, there is no
way of accessing the non-existing (or invalid) object. Thus, no
zombie.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Question regarding safety of a malloc() Andrew Shepson C Programming 6 06-03-2010 09:59 AM
Question regarding safety of a malloc() Stephan Beal C Programming 17 01-01-2009 02:47 PM
a question about exception safety in the book 'the c++ programminglanguage' unix.sh@gmail.com C++ 0 03-06-2008 04:39 PM
while executing my client program i get the exception javax.naming.LinkException: [Root exception is javax.naming.LinkException: [Root exception is javax.naming.NameNotFoundException: remaining if plz anybody know how to solve this problem then mahesh Java 0 03-08-2007 12:26 PM
Safety regarding USB devices xiongnu@my-deja.com Digital Photography 12 12-18-2005 02:20 AM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57