Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Order of destruct of local variables

196 views
Skip to first unread message

rkl...@gmail.com

unread,
Jul 21, 2008, 6:31:10 AM7/21/08
to
Hi,

Is the order of destruction of local variables of the function defined
in the C++ standard? For example in the following function, is it
always guaranteed that oAB is destroyed before oAC?

struct AB{
~AB(){}
};

struct AC{
~AC(){}
};

int main(){
AB oAB;
AC oAC;
}

I think the standard has reference only to the order of destruction of
static local variables, but not so much on the order for local
variables with auto storage.

Regards,
Dabs

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Greg Herlihy

unread,
Jul 21, 2008, 4:36:23 PM7/21/08
to
On Jul 21, 3:31 am, rkld...@gmail.com wrote:
> Is the order of destruction of local variables of the function defined
> in the C++ standard? For example in the following function, is it
> always guaranteed that oAB is destroyed before oAC?
>
> struct AB{
> ~AB(){}
>
> };
>
> struct AC{
> ~AC(){}
>
> };
>
> int main(){
> AB oAB;
> AC oAC;
>
> }

Yes, the C++ Standard does guarantee that local objects are destroyed
in the reverse order of their declaration:

"On exit from a scope (however accomplished), destructors are
called for all constructed objects with automatic storage duration
(named objects or temporaries) that are declared in that scope, in the
reverse order of their declaration." [§6.6/2]

Of course, temporaries cannot be declared (but that issue has already
been reported).

Nonetheless, any code that depended on this behavior would probably be
difficult to maintain - because the likelihood that the order of
declaration might change due to a future edit - seems rather high. At
the very least, I would create an inner scope solely for the purpose
of ensuring the proper order of destruction:

int main()
{
AB oAB;

{
AC oAC;
...
}
}

Greg

Alberto Ganesh Barbati

unread,
Jul 21, 2008, 5:16:29 PM7/21/08
to
rkl...@gmail.com ha scritto:

> Hi,
>
> Is the order of destruction of local variables of the function defined
> in the C++ standard? For example in the following function, is it
> always guaranteed that oAB is destroyed before oAC?
>
> struct AB{
> ~AB(){}
> };
>
> struct AC{
> ~AC(){}
> };
>
> int main(){
> AB oAB;
> AC oAC;
> }

Exactly the opposite. oAC is guaranteed to be destroyed before oAB.

> I think the standard has reference only to the order of destruction of
> static local variables, but not so much on the order for local
> variables with auto storage.

It's specified in 6.6/2. Local variables are destroyed in the reverse
order of their construction. Such guarantee is essential in scenarios
like this:

int main()
{
A a;
B b(&a); // stores a pointer to a
}

the destructor of b shall execute before the destructor of a, otherwise
b would remain with a dangling pointer while executing its destructor.

HTH,

Ganesh

Thomas Maeder

unread,
Jul 21, 2008, 5:19:12 PM7/21/08
to
rkl...@gmail.com writes:

> Is the order of destruction of local variables of the function
> defined in the C++ standard?

Yes.


> For example in the following function, is it always guaranteed that
> oAB is destroyed before oAC?

No. oAB is guaranteed to be destructed *after* oAC.


> struct AB{
> ~AB(){}
> };
>
> struct AC{
> ~AC(){}
> };
>
> int main(){
> AB oAB;
> AC oAC;
> }
>
> I think the standard has reference only to the order of destruction
> of static local variables, but not so much on the order for local
> variables with auto storage.

See §6.6 of the 1998 ISO C++ Standard.

LR

unread,
Jul 21, 2008, 5:19:25 PM7/21/08
to
rkl...@gmail.com wrote:

> Is the order of destruction of local variables of the function defined
> in the C++ standard? For example in the following function, is it
> always guaranteed that oAB is destroyed before oAC?

I think that should be the other way around, oAC will be destroyed
before oAB.

> int main(){
> AB oAB;
> AC oAC;
> }


>From the 2007-10-22 working draft, N2461, 6.6 Jump Statements (2),
"On exit from a scope (however accomplished), destructors (12.4) are


called for all constructed objects with automatic

storage duration (3.7.2) (named objects or temporaries) that are
declared in that scope, in the reverse order of their
declaration."

Same or similar in ISO/IEC 14882:1998(E).

LR

Thomas Lehmann

unread,
Jul 21, 2008, 5:17:43 PM7/21/08
to
On 21 Jul., 12:31, rkld...@gmail.com wrote:
> Hi,
>
> Is the order of destruction of local variables of the function defined
> in the C++ standard? For example in the following function, is it
> always guaranteed that oAB is destroyed before oAC?
>
> struct AB{
> ~AB(){}
>
> };
>
> struct AC{
> ~AC(){}
>
> };
>
> int main(){
> AB oAB;
> AC oAC;
>
> }
>
> I think the standard has reference only to the order of destruction of
> static local variables, but not so much on the order for local
> variables with auto storage.

Don't rely on any order! This is the best choice for you to avoid
running into undefined behaviour! If you need ordered deletion than
write a little tool class for that! I have managed it this way:

int main()
{
AutoCleanup autoCleanup;
AB* ab = autoCleanup(new AB);
AC* ac = autoCleanup(new AC);
return 0;
}//main

"ac" will be destroyed before "ab"!

ThosRTanner

unread,
Jul 21, 2008, 5:20:25 PM7/21/08
to
On Jul 21, 11:31 am, rkld...@gmail.com wrote:
> Hi,
>
> Is the order of destruction of local variables of the function defined
> in the C++ standard? For example in the following function, is it
> always guaranteed that oAB is destroyed before oAC?

> struct AB{
> ~AB(){}
>
> };
>
> struct AC{
> ~AC(){}
>
> };
>
> int main(){
> AB oAB;
> AC oAC;
>
> }
>
> I think the standard has reference only to the order of destruction of
> static local variables, but not so much on the order for local
> variables with auto storage.
>

I'm pretty sure they are destroyed in reverse order of construction,
so oAC will be destroyed FIRST.

In a slightly more complex situation, oAC could possibly be
constructed with a reference to oAB as an argument, and bad things
could happen if oAB was destroyed before oAC, so I'm not sure how much
choice the compiler has in the matter, even if it's not specified in
the standard.

Alberto Ganesh Barbati

unread,
Jul 22, 2008, 1:15:15 AM7/22/08
to
Thomas Lehmann ha scritto:

> On 21 Jul., 12:31, rkld...@gmail.com wrote:
>>
>> I think the standard has reference only to the order of destruction of
>> static local variables, but not so much on the order for local
>> variables with auto storage.
>
> Don't rely on any order! This is the best choice for you to avoid
> running into undefined behaviour!

That would be very unwise. The order of destruction is guaranteed, so it
good to be aware of it and I see nothing wrong in relying on it.

> running into undefined behaviour! If you need ordered deletion than
> write a little tool class for that! I have managed it this way:
>
> int main()
> {
> AutoCleanup autoCleanup;
> AB* ab = autoCleanup(new AB);
> AC* ac = autoCleanup(new AC);
> return 0;
> }//main
>
> "ac" will be destroyed before "ab"!
>

Why making things more complex that they are? What's the advantage of
this code with the more simple and obvious:

int main()
{
AB ab;
AC ac;
return 0;
} // "ac" will be destroyed before "ab"!

?

Just my opinion,

Ganesh

Thomas Lehmann

unread,
Jul 22, 2008, 5:31:22 PM7/22/08
to
> > int main()
> > {
> > AutoCleanup autoCleanup;
> > AB* ab = autoCleanup(new AB);
> > AC* ac = autoCleanup(new AC);
> > return 0;
> > }//main
>
> > "ac" will be destroyed before "ab"!
>
> Why making things more complex that they are? What's the advantage of
> this code with the more simple and obvious:
>
> int main()
> {
> AB ab;
> AC ac;
> return 0;
> } // "ac" will be destroyed before "ab"!

I have been reading "order of destruct" and with members you will
have to problem I was talking about. Sorry! Your code is fine!

Le Chaud Lapin

unread,
Jul 22, 2008, 5:58:15 PM7/22/08
to
On Jul 21, 4:17 pm, Thomas Lehmann <t.lehm...@rtsgroup.net> wrote:
> Don't rely on any order! This is the best choice for you to avoid
> running into undefined behaviour! If you need ordered deletion than
> write a little tool class for that! I have managed it this way:
>
> int main()
> {
> AutoCleanup autoCleanup;
> AB* ab = autoCleanup(new AB);
> AC* ac = autoCleanup(new AC);
> return 0;
>
> }//main
>
> "ac" will be destroyed before "ab"!

This seems a bit paradoxical. On the one hand, you are saying one
should not relie on order of destruction. On the other, you are saying
one should rely on the order of destruction of ab and ac to achieve
guaranteed order of destruction of AB and AC. :)

I have to agree with Alberto here. This is a feature of C++ that the
language designer deliberately and conscientiously provided to us to
use.

But there is something more fundamental going on: There was never a
choice to begin with. This illustrates, IMHO, an excellent opportunity
to test mindset when programming (engineering).

Suppose instead that you were the language designer, and someone asked
you to test your intuition to determine the proper order of
destruction. Your choices are:

1. FIFO (born first die first)
2. LIFO (born first die last)
3. Whatever

I contend that a good engineering mindset in the context of
computation should immediately eliminate #3 from consideration. Since
we are talking about construction/deconstruction, we should intuitvely
known that #1 or #2 is the correct answer, *without* experimentation.
Shortly thereafter, even a vague understanding of the mechanisms of
memory allocation on stack and heap would give preference to 2.

As often happens, once one has used #2 in practice for years, s/he
will have discovered an enumerable number of situations where the more
"beautiful" choice, #2, was not just a matter of aesthetics, but
necessity.

-Le Chaud Lapin-

Dan Barbus

unread,
Jul 23, 2008, 4:36:39 AM7/23/08
to
> Don't rely on any order! This is the best choice for you to avoid
> running into undefined behaviour! If you need ordered deletion than
> write a little tool class for that!
>
> AutoCleanup autoCleanup;
> AB* ab = autoCleanup(new AB);
> AC* ac = autoCleanup(new AC);
>
> "ac" will be destroyed before "ab"!

Actually, yes, rely on the order. It is guaranteed, and very useful.
Consider this code (used when working with boost serialization):

{
SomeClass *obj = new SomeClass();
>1> std::ofstream out("file.xml");
>2> archive::xml_oarchive oarch(out);
oarch << boost::serialization::make_nvp<SomeClass>("ObjData",
*obj);
return obj;
}

Here, you are guaranteed that the 'out' object (1) is valid past the
scope of 'oarch' (2), and still valid in oarch's destructor. Trying to
build around this, (to add extra code to get extra insurance the
destruction order is valid), complicates the code unnecessarily (using
extra accolades, dynamically allocating the memory or using smart
pointers, etc) and makes it uglier and harder to understand.

Regards,
Dan

Joshua...@gmail.com

unread,
Jul 23, 2008, 9:36:23 PM7/23/08
to
On Jul 22, 2:58 pm, Le Chaud Lapin <jaibudu...@gmail.com> wrote:
> Suppose instead that you were the language designer, and someone asked
> you to test your intuition to determine the proper order of
> destruction. Your choices are:
>
> 1. FIFO (born first die first)
> 2. LIFO (born first die last)
> 3. Whatever
>
> I contend that a good engineering mindset in the context of
> computation should immediately eliminate #3 from consideration. Since
> we are talking about construction/deconstruction, we should intuitvely
> known that #1 or #2 is the correct answer, *without* experimentation.

Actually, no. This reasoning does not hold in all cases. I just had a
rather long argument with a Java friend of mine over whether this
should always be the case. It is in Java. C++ is more lax than your a
priori reasoning would show. For example, the following program has
unspecified, but not undefined, behavior:

#include <iostream>
int foo() { std::cout << "foo" << std::endl; return 0; }
int bar() { std::cout << "bar" << std::endl; return 0; }
void baz(int , int ) {}
int main() { baz(foo(), bar()); }

The order of argument evaluation, i.e. whether foo or bar is called
first, is left unspecified. An implementation is free to choose either
order, and it does not have to be internally consistent. It could
"flip a coin" at every compile to pick an order. The reason for this,
and basically the lack of specified order in all similar subexpression
evaluation, is for efficiency. If you allow the compiler to pick
either order, it's possible that the compiler can generate better
code.


Also, to get back to the first point of this thread. The big reason
why the order of destruction of local objects is defined this way is
RAII. One acquires resources in constructors, and then one releases
them in destructors. It's generally the case you want to release
resources in the opposite order you acquired them. Add exceptions to
the mix, and this order of destruction is required for writing
sensible code.

Le Chaud Lapin

unread,
Jul 24, 2008, 1:50:27 AM7/24/08
to
On Jul 23, 8:36 pm, JoshuaMaur...@gmail.com wrote:
> On Jul 22, 2:58 pm, Le Chaud Lapin <jaibudu...@gmail.com> wrote:
> #include <iostream>
> int foo() { std::cout << "foo" << std::endl; return 0; }
> int bar() { std::cout << "bar" << std::endl; return 0; }
> void baz(int , int ) {}
> int main() { baz(foo(), bar()); }

> The order of argument evaluation, i.e. whether foo or bar is called
> first, is left unspecified. An implementation is free to choose either
> order, and it does not have to be internally consistent. It could
> "flip a coin" at every compile to pick an order. The reason for this,
> and basically the lack of specified order in all similar subexpression
> evaluation, is for efficiency. If you allow the compiler to pick
> either order, it's possible that the compiler can generate better
> code.

I think this example would not be applicable because it presumes that
one might infer that which has already been preempted by specification
- that there is no order. In the example I gave, where one statement
follows the other, it is understood that one statement completes
before the other.

You wrote:

> Also, to get back to the first point of this thread. The big reason
> why the order of destruction of local objects is defined this way is
> RAII. One acquires resources in constructors, and then one releases
> them in destructors. It's generally the case you want to release
> resources in the opposite order you acquired them.

Why? On what basis are you allowed to claim, "it is generally the
case"? :)

It is your intuition, gained from a combination of experience and raw
insight. We are essentially saying the same thing:

I wrote:

> I contend that a good engineering mindset in the context of
> computation should immediately eliminate #3 from consideration. Since
> we are talking about construction/deconstruction, we should intuitvely
> known that #1 or #2 is the correct answer, *without* experimentation.

> Shortly thereafter, even a vague understanding of the mechanisms of
> memory allocation on stack and heap would give preference to 2.

You wrote:

> Add exceptions to
> the mix, and this order of destruction is required for writing
> sensible code.

I wrote:

> As often happens, once one has used #2 in practice for years, s/he
> will have discovered an enumerable number of situations where the more
> "beautiful" choice, #2, was not just a matter of aesthetics, but
> necessity.

So in this case, the necessity stems from exceptions.

-Le Chaud Lapin-

Alberto Ganesh Barbati

unread,
Jul 24, 2008, 7:15:34 AM7/24/08
to
Joshua...@gmail.com ha scritto:

> On Jul 22, 2:58 pm, Le Chaud Lapin <jaibudu...@gmail.com> wrote:
>> Suppose instead that you were the language designer, and someone asked
>> you to test your intuition to determine the proper order of
>> destruction. Your choices are:
>>
>> 1. FIFO (born first die first)
>> 2. LIFO (born first die last)
>> 3. Whatever
>>
>> I contend that a good engineering mindset in the context of
>> computation should immediately eliminate #3 from consideration. Since
>> we are talking about construction/deconstruction, we should intuitvely
>> known that #1 or #2 is the correct answer, *without* experimentation.

Well, programmers versed in garbage collected languages might disagree.
In such languages, not only objects are not necessarily destroyed when
their variables exit from scope, but the order of destruction is
unspecified unless there is a dependency between the objects themselves.

> Actually, no. This reasoning does not hold in all cases. I just had a
> rather long argument with a Java friend of mine over whether this
> should always be the case. It is in Java. C++ is more lax than your a
> priori reasoning would show. For example, the following program has
> unspecified, but not undefined, behavior:
>
> #include <iostream>
> int foo() { std::cout << "foo" << std::endl; return 0; }
> int bar() { std::cout << "bar" << std::endl; return 0; }
> void baz(int , int ) {}
> int main() { baz(foo(), bar()); }

This example is a totally different issue and so it can't be used as an
argument against what Le Chaud Lapin said. An expression used a function
argument cannot refer to another expression used as another function
argument. Temporaries are not like variables. The construction of a
variable can refer to any other variable in scope and so it must be
allowed to rely on the fact that the lifetime of such variable is
already started and is not ending too soon.

> Also, to get back to the first point of this thread. The big reason
> why the order of destruction of local objects is defined this way is
> RAII. One acquires resources in constructors, and then one releases
> them in destructors. It's generally the case you want to release
> resources in the opposite order you acquired them. Add exceptions to
> the mix, and this order of destruction is required for writing
> sensible code.
>

The order of destruction is common sense, it's not there because of
RAII, although it's an essential ingredient of the RAII recipe. The key
point in RAII is the guarantee that destructors are called as soon as
the variable exits from scope and that's why RAII is not a good idiom in
garbage collected languages.

Just my opinion,

Ganesh

Bart van Ingen Schenau

unread,
Jul 24, 2008, 6:08:12 PM7/24/08
to
Joshua...@gmail.com wrote:

> Also, to get back to the first point of this thread. The big reason
> why the order of destruction of local objects is defined this way is
> RAII.

I don't think that is true.
Rather, it is the other way around. We can have RAII because destruction
is in the reverse order of construction.

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

Joshua...@gmail.com

unread,
Jul 24, 2008, 6:10:28 PM7/24/08
to
On Jul 24, 4:15 am, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:
> JoshuaMaur...@gmail.com ha scritto:

> > On Jul 22, 2:58 pm, Le Chaud Lapin <jaibudu...@gmail.com> wrote:
> >> Suppose instead that you were the language designer, and someone asked
> >> you to test your intuition to determine the proper order of
> >> destruction. Your choices are:
>
> >> 1. FIFO (born first die first)
> >> 2. LIFO (born first die last)
> >> 3. Whatever
>
> >> I contend that a good engineering mindset in the context of
> >> computation should immediately eliminate #3 from consideration. Since
> >> we are talking about construction/deconstruction, we should intuitvely
> >> known that #1 or #2 is the correct answer, *without* experimentation.
> [Omitting some - Josh]

> This example is a totally different issue and so it can't be used as an
> argument against what Le Chaud Lapin said.
> [Omitting some - Josh]

I am just arguing against his claim that "We should intuitively know
that #1 or #2 is the correct answer, *without* explanation." That
argument sounds like it is claiming that a well formed construct
should not have "non-determinate" / unspecified / implementation
defined behavior, whereas there are plenty of C++ constructs which do
with good reason. The order of stack destructors is not one of them,
but the reasons for this order should not be hand-waved "without
explanation".


On Jul 24, 4:15 am, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:


> The order of destruction is common sense, it's not there because of
> RAII, although it's an essential ingredient of the RAII recipe. The key
> point in RAII is the guarantee that destructors are called as soon as
> the variable exits from scope and that's why RAII is not a good idiom in
> garbage collected languages.

I must have missed something. RAII, as I understand it, is not
possible in garbage collected languages like Java. RAII is the idiom
of acquiring resources in constructors and freeing those resources in
destructors. Garbage collected languages like Java, which have most /
all objects in the heap, do not have destructors, and thus cannot have
RAII. (Arguably, you can have garbage collection and stack
destructors, and thus get some sort of RAII with garbage collection,
but I don't know a language offhand which does that.) (Finalizers are
a poor substitute, as you are not guaranteed the order they are called
in, or that they are called at all. Using finalizers also puts a great
deal of overhead on the garbage collector, whereas destructors
generally have no overhead compared to freeing the resource manually.
Finally blocks are a better substitute, but using finally blocks
limits that resource to that scope, unlike RAII, and the code to
allocate the resource and deallocate the resource are not in the same
spot, unlike C++ RAII where both are done by simply creating the
object.) RAII, allowed by stack objects with destructors, is one of
the major reasons I prefer C++ to Java.

Joshua...@gmail.com

unread,
Jul 24, 2008, 7:22:17 PM7/24/08
to
On Jul 24, 3:08 pm, Bart van Ingen Schenau <b...@ingen.ddns.info>
wrote:

> JoshuaMaur...@gmail.com wrote:
> > Also, to get back to the first point of this thread. The big reason
> > why the order of destruction of local objects is defined this way is
> > RAII.
>
> I don't think that is true.
> Rather, it is the other way around. We can have RAII because destruction
> is in the reverse order of construction.

I cannot comment offhand on the intent of Bjarne Stroustrup when
designing C++. I would like to think he designed C++ with RAII in
mind. IMHO, RAII is at the heart of good C++ style. I do not believe
it was an accident that C++ supports what we call "RAII". I think it
was a very conscious design choice, very much tied to OOP in general.

--

Le Chaud Lapin

unread,
Jul 24, 2008, 9:58:15 PM7/24/08
to
On Jul 24, 5:10 pm, JoshuaMaur...@gmail.com wrote:
> I am just arguing against his claim that "We should intuitively know
> that #1 or #2 is the correct answer, *without* explanation." That
> argument sounds like it is claiming that a well formed construct
> should not have "non-determinate" / unspecified / implementation
> defined behavior, whereas there are plenty of C++ constructs which do
> with good reason. The order of stack destructors is not one of them,
> but the reasons for this order should not be hand-waved "without
> explanation".

"Experimentation", not "explanation", and no, that's not what I am
saying. :)

I am saying that, given two choices in such situations, it is
generally a good idea to choose the one that is most beautiful, if it
appears, at very first sight, that all three choices (FIFO/LIFO/
Whatever) are equally valid and equally inconsequential. Then, after
experimentation, it will often be discovered that there was no choice
at all. In vast majority of cases, the most beautiful choice will
have, in fact, been only choice, only this was not yet known.

A similar but poor example is order of construction and destruction of
arrays. Unfotunately, as experienced programmers, we all know that
construction starts at index 0 and ends at (N-1), whereas destruction
starts at index (N-1) and ends at 0. But even if we did not know this
rule, our experience/insight into what generally goes on inside C++
execution model would lead any of us to quickly conclude that the LIFO
model is correct. But what about someone who has only recently gained
insight into the operation of automatic variables, the heap, and the
stack? Such an individual, when presented with the question:

"If objects are constructed in order from 0 to N-1, do you think there
should be any particular order in which should be destructed?"

A few reponders might reply:

"Well, since the array was constructed starting at 0, I guess
destruction starting at 0 too would be nice."

Again, this is a bad example because the answer is too easy/obvious.
However, in my career, I have encountered many frighteningly
complicated but beautifully complex systems where the designer
(partially me) is so deep in the the forest that no trees can be
seen. I apply this this principal as my crutch, mumbling in my
disillusionment:

1. "FIFO or LIFO, probably FIFO."
2. "Symmetry is good."
3. "Zero seems like never a possibility, but zero does not hurt, and
makes code cleaner, so use it and stop asking why."
4. "You've witten code for 7 patterns, but there is an 8th pattern
sitting there unimplemented. Looks impotent and useless. Nevermind,
support it anyway. Will not slow down code, only bloats it by a few
bytes, and keeps system regular."

...and so on.

Almost invariably, I'd say 95% of the time, I will later have an
epiphanous moment where I think..."Ohh...no...I should have allowed
for 0!!!! or....I could kick...myself....arrgg..I *need* that 8th
situation...I have to make quick update to fix the..."

And then I realize that there is nothing to worry about, because zero
is included. The 8th is covered. I adhered to The Principle. :)

-Le Chaud Lapin-

Eugene Gershnik

unread,
Jul 25, 2008, 4:46:32 AM7/25/08
to
On Jul 24, 4:15 am, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:
> JoshuaMaur...@gmail.com ha scritto:

>
> > On Jul 22, 2:58 pm, Le Chaud Lapin <jaibudu...@gmail.com> wrote:
> >> Suppose instead that you were the language designer, and someone asked
> >> you to test your intuition to determine the proper order of
> >> destruction. Your choices are:
>
> >> 1. FIFO (born first die first)
> >> 2. LIFO (born first die last)
> >> 3. Whatever
>
> >> I contend that a good engineering mindset in the context of
> >> computation should immediately eliminate #3 from consideration. Since
> >> we are talking about construction/deconstruction, we should intuitvely
> >> known that #1 or #2 is the correct answer, *without* experimentation.
>
> Well, programmers versed in garbage collected languages might disagree.
> In such languages, not only objects are not necessarily destroyed when
> their variables exit from scope, but the order of destruction is
> unspecified unless there is a dependency between the objects themselves.

I think this is a misconception. Collection of garbage memory is *not*
destruction[1]. The only GC language I know that also supports
destruction *in the language* does it based on scope and in the same
order as C++. See C#'s 'using' construct for details.
Other GC languages I know don't support destruction at all. If such
functionality is necessary the programmer has to manually supply all
those destory(), dispose(), close() etc. methods and call them when
necessary. Even there the good practice is usually to make these calls
in the opposite order of object construction/acquisition. Below is a
canonical piece of code that does perform guaranteed manual
destruction of two objects in Java. Notice how simple requirements of
scope cause the order of destruction to mimic the one of C++.

Foo foo = new Foo();
try
{
//use foo...
Bar bar = new Bar();
try
{
//use foo and bar...
}
finally
{
bar.close();
}
}
finally
{
foo.destroy();
}


[1] - I am ignoring mostly useless 'finalizers' for simplicity

--
Eugene

Nominal Pro

unread,
Jul 25, 2008, 4:43:42 AM7/25/08
to
On Jul 24, 6:15 am, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
wrote:
> JoshuaMaur...@gmail.com ha scritto:

> > On Jul 22, 2:58 pm,Le Chaud Lapin<jaibudu...@gmail.com> wrote:
> >> I contend that a good engineering mindset in the context of
> >> computation should immediately eliminate #3 from consideration. Since
> >> we are talking about construction/deconstruction, we should intuitvely
> >> known that #1 or #2 is the correct answer, *without* experimentation.
>
> Well, programmers versed in garbage collected languages might disagree.
> In such languages, not only objects are not necessarily destroyed when
> their variables exit from scope, but the order of destruction is
> unspecified unless there is a dependency between the objects themselves.

I agree. Le Chaud Lapin's #1 or #2 merely seems "intuitive" from a C++
mindset. It is not the mindset of someone who programs in a garbage
collected language.

> The order of destruction is common sense, it's not there because of
> RAII, although it's an essential ingredient of the RAII recipe. The key
> point in RAII is the guarantee that destructors are called as soon as
> the variable exits from scope and that's why RAII is not a good idiom in
> garbage collected languages.
>

True. Going back to the OP, both automatic variables were in the same
scope and thus going out of scope at the same time. So why should
their order of destruction matter? If LIFO order of destruction is
required, I would use a nested scope, like this:

int main()
{
AB oAB;
{
AC oAC;
}
}

Alberto Ganesh Barbati

unread,
Jul 25, 2008, 2:04:42 PM7/25/08
to
Joshua...@gmail.com ha scritto:

You didn't miss anything. You have clearly expressed what I more
succinctly wrote, that is RAII is not a good idiom in Java (because it's
not practically possible). It seems that you and I completely agree on
this issue. My point was that the essential fact behind RAII is
precisely the guarantee that destructors are called and *when* this
should happen (something you don't have in Java). Once you have that,
it's just common sense that dictates the only sensible order in which
destructors for multiple objects should be called.

Ganesh

Francis Glassborow

unread,
Jul 25, 2008, 2:06:43 PM7/25/08
to
Nominal Pro wrote:

>
> True. Going back to the OP, both automatic variables were in the same
> scope and thus going out of scope at the same time. So why should
> their order of destruction matter?

Because sometimes the bodies of dtors rely on the existence of another
object. It would be a little weird if such reliance was for an object
that did not exist at construction time. LIFO effectively guarantees
that such dependencies will not fall foul of the required object being
destroyed too early.


If LIFO order of destruction is
> required, I would use a nested scope, like this:
>
> int main()
> {
> AB oAB;
> {
> AC oAC;
> }
> }
>
>

But what advantage does FIFO have to compensate for making it necessary
to write such code when oAC must be destroyed before oAB

Alberto Ganesh Barbati

unread,
Jul 25, 2008, 2:05:15 PM7/25/08
to
Eugene Gershnik ha scritto:

> Below is a
> canonical piece of code that does perform guaranteed manual
> destruction of two objects in Java. Notice how simple requirements of
> scope cause the order of destruction to mimic the one of C++.
>
> Foo foo = new Foo();
> try
> {
> //use foo...
> Bar bar = new Bar();
> try
> {
> //use foo and bar...
> }
> finally
> {
> bar.close();
> }
> }
> finally
> {
> foo.destroy();
> }
>

Nice. 16 lines. Compared to two lines in C++. That's why I prefer C++
over Java.

Ganesh

Le Chaud Lapin

unread,
Jul 25, 2008, 8:20:01 PM7/25/08
to
On Jul 25, 3:43 am, Nominal Pro <majorsc...@gmail.com> wrote:
> I agree. Le Chaud Lapin's #1 or #2 merely seems "intuitive" from a C++
> mindset. It is not the mindset of someone who programs in a garbage
> collected language.

I don't mean to bash garbage-collected languages, but I suspect that a
decade or so from now, the LIFO model, in the context of OO-
programming, will be described by language theorists not just as a
peculiarity of C++ and its friends, but a fundamental virtue that was
forsaken by languages that essentially discarded it. Also note that
the principle I speak of applies not just to computer programming, but
engineering in general.

> True. Going back to the OP, both automatic variables were in the same
> scope and thus going out of scope at the same time. So why should
> their order of destruction matter? If LIFO order of destruction is
> required, I would use a nested scope, like this:
>
> int main()
> {
> AB oAB;
> {
> AC oAC;
> }
>
> }

That will not work for an array of 8192 Foo's, where each Foo adds to
a stack-like structure some kind of element, and therefore requires
that the elements be removed and destroyed in the reverse order in
which they were stacked. There are other reasons, like memory
management. For many type of heap managers, much less stress
(fragmentation, housework, etc.) is placed on the heap manager if the
memory is freed in the reverse order it was allocated. With C++
automatic objects that allocate from the heap, this happens
automatically.

However, I would like to emphasize that it was not C++, or C, or
Pascal, or assembly, or even BASIC that guided me toward this mindset.
It was the notion of the Dijkstra/von Neumann architecture, a
fundamentally-pervasive model that practically begs for a LIFO as the
preferred lifetime model.

-Le Chaud Lapin-

Bart van Ingen Schenau

unread,
Jul 25, 2008, 8:19:47 PM7/25/08
to
Joshua...@gmail.com wrote:

> On Jul 24, 3:08 pm, Bart van Ingen Schenau <b...@ingen.ddns.info>
> wrote:
>> JoshuaMaur...@gmail.com wrote:
>> > Also, to get back to the first point of this thread. The big reason
>> > why the order of destruction of local objects is defined this way
>> > is RAII.
>>
>> I don't think that is true.
>> Rather, it is the other way around. We can have RAII because
>> destruction is in the reverse order of construction.
>
> I cannot comment offhand on the intent of Bjarne Stroustrup when
> designing C++. I would like to think he designed C++ with RAII in
> mind.

As far as I can determine, RAII was invented (by Bjarne) for dealing
with resource leaks in the face of exceptions.
As exceptions came relatively late to the development of C++, I don't
think that RAII was the reason to have destruction of automatic
variables in the reverse order of construction.
I think it is much more likely that this was a consequence of how the
early C-with-Classes and C++ translators produced the intermediate C
code, but unless Bjarne speaks up, we will never know this for sure.

> IMHO, RAII is at the heart of good C++ style.

No disagreement there. But typically, what is good style is only
recognised once a language has been used for some time.

> I do not believe
> it was an accident that C++ supports what we call "RAII". I think it
> was a very conscious design choice, very much tied to OOP in general.

RAII is much more related to exceptions than to OOP.
In fact, I can't think of any other language that supports OOP and uses
the RAAI idiom.
To my knowledge, the majority of OOP languages makes heavy use of
garbage collection, which is completely unsuitable for RAII.

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://c-faq.com/
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

[ See http://www.gotw.ca/resources/clcm.htm for info about ]

Alex

unread,
Jul 25, 2008, 8:25:28 PM7/25/08
to
On Jul 25, 4:46 am, Eugene Gershnik <gersh...@gmail.com> wrote:

> Collection of garbage memory is *not* destruction[1].

True, but automatic and deterministic destruction is tightly
associated with (and of indispensable value for) garbage collection.

> Foo foo = new Foo();
> try
> {
> //use foo...
> Bar bar = new Bar();
> try
> {
> //use foo and bar...
> }
> finally
> {
> bar.close();
> }}
>
> finally
> {
> foo.destroy();
>
> }

Excellent example of Java limitation compared to C++ - you get
automatic garbage collection for allocated memory at a price of having
to worry about manually collecting numerous other resources (such as
file handles, network connections etc).

Alex

Eugene Gershnik

unread,
Jul 26, 2008, 3:27:15 PM7/26/08
to
On Jul 25, 5:25 pm, Alex <ale...@gmail.com> wrote:
> On Jul 25, 4:46 am, Eugene Gershnik <gersh...@gmail.com> wrote:
>
> > Collection of garbage memory is *not* destruction[1].
>
> True, but automatic and deterministic destruction is tightly
> associated with (and of indispensable value for) garbage collection.

That's a very surprising statement. Care to elaborate?

As far as I can see destruction is more or less orthogonal to garbage
collection. In GC languages the former deals with non-memory resources
(UI gadgets, network connections, DB sessions, object associations
etc. etc.). The later deals with one specific resource - memory, that
some people consider special because of its impact on type safety[1].
An object such as network connection is at the same time a memory and
a non-memory resource. It can be separately destroyed and then, later,
its memory garbage collected. Note that in general you cannot leave
the destructor call to the garbage collector because of object
dependency and timing issues. Hence the finalizers that were meant to
do just that are largely useless. Often the only useful thing a
finalizer can do when it encounters an object that ought to be but
wasn't separately destroyed is to report a 'logic error'

I have never used a garbage collector in C++ but I would expect it to
work along the same principles. E.g. delete p; under GC ought to
invoke the destructor but leave the memory around (as if having empty
operator delete()) for the collector to pick up later.

[1] - I don't buy this argument since I don't consider type safety any
more important than safety of everything else but that's a topic for
another discussion.

--
Eugene

Joshua...@gmail.com

unread,
Jul 27, 2008, 5:18:50 AM7/27/08
to
On Jul 25, 5:19 pm, Bart van Ingen Schenau <b...@ingen.ddns.info>
wrote:

> As far as I can determine, RAII was invented (by Bjarne) for dealing
> with resource leaks in the face of exceptions.
> As exceptions came relatively late to the development of C++, I don't
> think that RAII was the reason to have destruction of automatic
> variables in the reverse order of construction.
> I think it is much more likely that this was a consequence of how the
> early C-with-Classes and C++ translators produced the intermediate C
> code, but unless Bjarne speaks up, we will never know this for sure.

On Jul 25, 5:19 pm, Bart van Ingen Schenau <b...@ingen.ddns.info>


wrote:
> JoshuaMaur...@gmail.com wrote:
> > I do not believe
> > it was an accident that C++ supports what we call "RAII". I think it
> > was a very conscious design choice, very much tied to OOP in general.
>
> RAII is much more related to exceptions than to OOP.
> In fact, I can't think of any other language that supports OOP and uses
> the RAAI idiom.
> To my knowledge, the majority of OOP languages makes heavy use of
> garbage collection, which is completely unsuitable for RAII.

You're right. RAII is not necessarily a part of OOP, but I tend to
think
of it as strongly tied to OOP. RAII is the practice of making sure
all resources are strictly owned, that they always have some owner
who will free them, and eventually this ownership chain goes back
to an object on the stack or a static object. I think Java and other
OOP languages that do not have destructors are missing this vital
idiom
which reinforces resource ownership.

--

David Abrahams

unread,
Jul 27, 2008, 5:28:18 AM7/27/08
to

on Thu Jul 24 2008, JoshuaMaurice-AT-gmail.com wrote:

> On Jul 24, 3:08 pm, Bart van Ingen Schenau <b...@ingen.ddns.info>
> wrote:
>> JoshuaMaur...@gmail.com wrote:
>> > Also, to get back to the first point of this thread. The big reason
>> > why the order of destruction of local objects is defined this way is
>> > RAII.
>>
>> I don't think that is true.
>> Rather, it is the other way around. We can have RAII because destruction
>> is in the reverse order of construction.
>
> I cannot comment offhand on the intent of Bjarne Stroustrup when
> designing C++. I would like to think he designed C++ with RAII in
> mind. IMHO, RAII is at the heart of good C++ style. I do not believe
> it was an accident that C++ supports what we call "RAII". I think it
> was a very conscious design choice, very much tied to OOP in general.

You are probably right, except that IMO it has little to do with OOP and
everything to do with value semantics.

--
Dave Abrahams
BoostPro Computing
http://www.boostpro.com

Nominal Pro

unread,
Jul 27, 2008, 5:23:49 PM7/27/08
to
On Jul 25, 7:20 pm, Le Chaud Lapin <jaibudu...@gmail.com> wrote:
> I don't mean to bash garbage-collected languages, but I suspect that a
> decade or so from now, the LIFO model, in the context of OO-
> programming, will be described by language theorists not just as a
> peculiarity of C++ and its friends, but a fundamental virtue that was
> forsaken by languages that essentially discarded it. Also note that
> the principle I speak of applies not just to computer programming, but
> engineering in general.

Languages that rely on garbage collection never "discarded" the C++
LIFO model. They were designed around garbage collection from the
start. It is also not a recent trend in language design either.
Smalltalk, which predates C++, used GC, as did LISP (starting in the
70s).

bjarne

unread,
Jul 27, 2008, 5:37:41 PM7/27/08
to
On Jul 25, 8:19 pm, Bart van Ingen Schenau <b...@ingen.ddns.info>
wrote:

> >> > Also, to get back to the first point of this thread. The big reason


> >> > why the order of destruction of local objects is defined this way
> >> > is RAII.
>
> >> I don't think that is true.
> >> Rather, it is the other way around. We can have RAII because
> >> destruction is in the reverse order of construction.
>
> > I cannot comment offhand on the intent of BjarneStroustrupwhen
> > designing C++. I would like to think he designed C++ with RAII in
> > mind.
>
> As far as I can determine, RAII was invented (by Bjarne) for dealing
> with resource leaks in the face of exceptions.
> As exceptions came relatively late to the development of C++, I don't
> think that RAII was the reason to have destruction of automatic
> variables in the reverse order of construction.
> I think it is much more likely that this was a consequence of how the
> early C-with-Classes and C++ translators produced the intermediate C
> code, but unless Bjarne speaks up, we will never know this for sure.
>
> > IMHO, RAII is at the heart of good C++ style.
>
> No disagreement there. But typically, what is good style is only
> recognised once a language has been used for some time.

Constructors and destructors are one of the oldest parts of C++
(together with features such as functions argument checking aka
"function prototypes"). They predate virtual functions and exceptions
by years. The notion, articulated at the time, was that a constructor
builds up the environment in which member functions execute and the
destructor tears down that environment. From that follows "first
constructed becomes last destroyed" (for both local variables and
members. Acquisition and release of resources were explicitly
mentioned in even the oldest notes I can find. The resource issue is
at the heart of the constructor/destructor design, and of C++. The
first resources mentioned (1980) were memory, locks, queues, and
thread handles.

-- Bjarne Stroustrup; http://www.research.att.com/~bs


--

Dave Harris

unread,
Jul 27, 2008, 5:35:17 PM7/27/08
to
da...@boostpro.com (David Abrahams) wrote (abridged):

> on Thu Jul 24 2008, JoshuaMaurice-AT-gmail.com wrote:
> > IMHO, RAII is at the heart of good C++ style. I do not
> > believe it was an accident that C++ supports what we call "RAII".
> > I think it was a very conscious design choice, very much tied
> > to OOP in general.
>
> You are probably right, except that IMO it has little to do with
> OOP and everything to do with value semantics.

Nowadays I see it in terms of class invariants, which I think are very OO.
If the class invariant says the object owns the resource, then when the
resource is freed the class invariant no longer holds and the object is
unusable. It's destroyed, in a profound and unavoidable sense. (Which
isn't to say its memory has been recovered, of course - that's a separate
issue.) C++ doesn't reify class invariants in the way that, eg, Eiffel
does, but the notion is reflected eg in the way virtual function
overrides behave as the object is destroyed.

And constructed. Java doesn't have destructors, but it does have
constructors and it seems slightly strange to me that in Java, calls to
virtual functions get directed to the most-derived class implementation,
even before that class's constructor has run and so before it has had a
chance to set up its invariants. Eiffel and Smalltalk have the same rule,
but those languages don't try to enforce module barriers between base
classes and derived classes, so they are more consistent. Java seems a
bit muddled in this.

Anyway, you could have destructors and RAII without value semantics. Just
create everything on the heap and delete it explicitly, and use some
other mechanism to get protection from exceptions and scope-based
destruction. (Many languages use mechanisms based on block-closures.)

-- Dave Harris, Nottingham, UK.

--

Alex

unread,
Jul 27, 2008, 5:36:50 PM7/27/08
to
On Jul 26, 3:27 pm, Eugene Gershnik <gersh...@gmail.com> wrote:
> On Jul 25, 5:25 pm, Alex <ale...@gmail.com> wrote:
>
> > On Jul 25, 4:46 am, Eugene Gershnik <gersh...@gmail.com> wrote:
>
> > > Collection of garbage memory is *not* destruction[1].
>
> > True, but automatic and deterministic destruction is tightly
> > associated with (and of indispensable value for) garbage collection.
>
> That's a very surprising statement. Care to elaborate?

Sure. The statement is surprising only if you consider garbage to be
the memory that is not needed any more and nothing else. So, in order
to be on the same page, we need to agree on the term "garbage". I am
using it as a generic term representing any resource that is held by a
program but is not needed any more.

> As far as I can see destruction is more or less orthogonal to garbage
> collection. In GC languages the former deals with non-memory resources
> (UI gadgets, network connections, DB sessions, object associations
> etc. etc.).

Just like memory allocation consumes available resources and can be
exhausted if allocated but not released, so can a DB connection or a
socket pool. From that point of view, when a resource is not needed
any more it becomes garbage that needs to be collected somehow. In C+
+, the most convenient way is to automatically do it for any type of
resource by wrapping it in a class and have it collected automatically
at destruction time. Memory garbage collector is useful in those cases
where it is not feasible to automatically release memory at
destruction time.

> The later deals with one specific resource - memory, that
> some people consider special because of its impact on type safety[1].
> An object such as network connection is at the same time a memory and
> a non-memory resource. It can be separately destroyed and then, later,
> its memory garbage collected. Note that in general you cannot leave
> the destructor call to the garbage collector because of object
> dependency and timing issues.

Exactly. And that makes Java-like garbage collection largely flawed -
it solves only part of a problem with a side-effect of loosing the
important capability to automatically release any other resources you
are holding.

Alex

--

Mathias Gaunard

unread,
Jul 27, 2008, 5:41:11 PM7/27/08
to
On 27 juil, 11:18, JoshuaMaur...@gmail.com wrote:
> You're right. RAII is not necessarily a part of OOP, but I tend to
> think
> of it as strongly tied to OOP.

On the contrary, it is the opposite of OOP.
OOP works with eternal-lifetime entities that you reference, RAII
works with limited-lifetime values that you can (or not) move or copy.

The fact of grouping and abstracting elements into an object is object-
based programming, not object-oriented programming.
Object-oriented programming does require it, but then it's more about
inheritance, ad-hoc polymorphism and pointer-like variables (entities)
everywhere.

Nominal Pro

unread,
Jul 27, 2008, 11:50:34 PM7/27/08
to
On Jul 24, 5:10 pm, JoshuaMaur...@gmail.com wrote:
> On Jul 24, 4:15 am, Alberto Ganesh Barbati <AlbertoBarb...@libero.it>
> wrote:
> > The order of destruction is common sense, it's not there because of
> > RAII, although it's an essential ingredient of the RAII recipe. The key
> > point in RAII is the guarantee that destructors are called as soon as
> > the variable exits from scope and that's why RAII is not a good idiom in
> > garbage collected languages.
>
> I must have missed something. RAII, as I understand it, is not
> possible in garbage collected languages like Java. RAII is the idiom
> of acquiring resources in constructors and freeing those resources in
> destructors. Garbage collected languages like Java, which have most /
> all objects in the heap, do not have destructors, and thus cannot have
> RAII. (Arguably, you can have garbage collection and stack
> destructors, and thus get some sort of RAII with garbage collection,
> but I don't know a language offhand which does that.)
> [--snip--]

C++/CLI supports both RAII and garbage collection. The destructors in C
++/CLI are invoked deterministically, while finalizers are invoked non-
deterministically. You can define both a destructor and finalizer for
a C++/CLI ref class. Then, if you declare an object of that class on
the stack, the destructor gets invoked when it goes out of scope. If
you create it from the garbage collected heap, the finalizer gets
invoked, unless you explicitly called the delete operator, which
invokes the destructor. The best of both worlds.

Eugene Gershnik

unread,
Jul 28, 2008, 4:32:26 AM7/28/08
to
On Jul 27, 2:36 pm, Alex <ale...@gmail.com> wrote:
> On Jul 26, 3:27 pm, Eugene Gershnik <gersh...@gmail.com> wrote:
>
> So, in order
> to be on the same page, we need to agree on the term "garbage". I am
> using it as a generic term representing any resource that is held by a
> program but is not needed any more.

Ok, this is a reasonable definition but note that it is not the one
usually used in term 'garbage collection'.

> Just like memory allocation consumes available resources and can be
> exhausted if allocated but not released, so can a DB connection or a
> socket pool. From that point of view, when a resource is not needed
> any more it becomes garbage that needs to be collected somehow.

[snip]

> And that makes Java-like garbage collection largely flawed -
> it solves only part of a problem with a side-effect of loosing the
> important capability to automatically release any other resources you
> are holding.

Well, yes, but the problem is that it is completely unclear how to
implement a general collector of general 'garbage'. Leaving reference
counting as a form of GC aside, the usual collector has to run
asynchronously with respect to the application code. The problem is
when to run the collector and in what order to collect. With memory
one can assume that

a) there is generally a lot of it
b) it is possible to know when we start to run out of it
c) collection of one piece of memory can be done independently of
another

With a general resource all these assumptions may be incorrect.
Resource can be relatively scarce (e.g. sockets) so waiting too long
to run the collector may cause exhaustion. Then how do you detect that
you don't have many transactions left in some 3rd party database?
Finally some resources rely on other resources existence during
destruction. A collector will have to ensure that objects are
destroyed in some predictable order (presumably LIFO, which brings as
back full circle to the topic of this thread) As far as I understand
ensuring such order might be very tricky for modern garbage collectors
(I am no expert on garbage collectors so I may be wrong here).

--
Eugene

Dave Harris

unread,
Jul 28, 2008, 2:37:25 PM7/28/08
to
ale...@gmail.com (Alex) wrote (abridged):

> Just like memory allocation consumes available resources and can
> be exhausted if allocated but not released, so can a DB connection
> or a socket pool. From that point of view, when a resource is not
> needed any more it becomes garbage that needs to be collected
> somehow. In C++, the most convenient way is to automatically do

> it for any type of resource by wrapping it in a class and have
> it collected automatically at destruction time.

Except that often when a resource is freed there needs to be some final
work done, eg flushing buffers, and this can fail, and destructors don't
have a good way to report failure. They can't return a function result to
their caller, and it's dangerous for them to use exceptions. Destructors
are a little bit too special.

And this is inherent in their being automatic. If they aren't explicitly
called then the caller isn't explicitly prepared to handle their errors.
The model of (eg) Smalltalk is more explicit, which is a burden for the
programmer but at least lets errors be handled in the usual way. I think
in C++ there is a tendency to sweep this problem under the carpet, and
people simply don't check, eg, the return code of fclose(), in
destructors. Out of sight is out of mind.

-- Dave Harris, Nottingham, UK.

--

Joshua...@gmail.com

unread,
Jul 28, 2008, 7:58:18 PM7/28/08
to
On Jul 28, 11:37 am, brang...@cix.co.uk (Dave Harris) wrote:
> And this [Destructors -Josh] is inherent in their being automatic.

> If they aren't explicitly
> called then the caller isn't explicitly prepared to handle their errors.
> The model of (eg) Smalltalk is more explicit, which is a burden for the
> programmer but at least lets errors be handled in the usual way. I think
> in C++ there is a tendency to sweep this problem under the carpet, and
> people simply don't check, eg, the return code of fclose(), in
> destructors. Out of sight is out of mind.

Conceptually speaking, acquiring a resource can fail. It's not ready,
there are none left, you didn't acquire it correctly, etc. If it does
fail, there might be a way to fix the problem, or you can report it to
the user. However, conceptually, freeing a resource should not
encounter a problem. You're just giving it back to the OS. Moreover,
if freeing some resource fails, there's not much you can do about it,
just log or report the error for later debugging and maybe kill the
process, which destructors allow you to do. Generally speaking, if
freeing a resource fails, you're probably fubar anyway.

Dave Harris

unread,
Jul 29, 2008, 5:28:19 PM7/29/08
to
Joshua...@gmail.com () wrote (abridged):

> However, conceptually, freeing a resource should not
> encounter a problem.

You snipped the part of my article where I explained why in practice it
might encounter a problem. Any work for the resource might be buffered up
for efficiency, and then done just before the resource is freed.


> Moreover, if freeing some resource fails, there's not much you can
> do about it, just log or report the error for later debugging
> and maybe kill the process, which destructors allow you to do.

But as usual with error handling, the point at which the error is
detected may not be the best place to decide how to handle it. If we
could throw an exception, that would be fine, but in practice throwing
exceptions from destructors is so dangerous that it's best avoided.

-- Dave Harris, Nottingham, UK.

--

0 new messages