Local objects in function not destructed on exception?

R

Robbie Hatley

I've been playing with "auto_ptr" and the "Resource Acquisition
Is Initialization" concept. On page 199 of Lippman's book
"Effective C++" he says "All active local class objects of a
function are guaranteed to have their destructors applied
before termination of the function by the exception handling
mechanism.".

I don't think that's true, though. The standard doesn't seem
to require it. Section 15.2 just says that all objects
constructed SINCE ENTERING A TRY BLOCK will be destructed
on transfer of control to a catch block. That's very different
from Lippman's statement.

I wrote this:


#include <iostream>
#include <string>
#include <memory>
#include <cstdlib>

using std::cout;
using std::endl;

class Vogon
{
public:
Vogon(int x) : Jeltz(x) {cout << "In parameterized constructor." << endl;}
~Vogon() {cout << "In destructor." << endl;}
void React ()
{
if (17 == Jeltz) throw 17; // Barf if 17==Jeltz
cout << "You entered " << Jeltz
<< ". (But don't enter \"17\"!)" << endl;
}
void Poetry () {cout << "Oh, furdled gruntbuggly!" << endl;}
private:
int Jeltz;
};

int main(int, char* A[])
{
int X = atoi(A[1]);
std::auto_ptr<Vogon> Vog (new Vogon(X));
Vog->React(); // If user used command-line arg. "17", throw uncaught
exception.
Vog->Poetry(); // Even though the sound of it is somewhat quite atrocious.
return 0; // Release resources???
}


But if you type "auto_ptr-test 17" it barfs without ever calling
the destructor:


wd=C:\RHE\src\test
%auto_ptr-test 45
In parameterized constructor.
You entered 45. (But don't enter "17"!)
Oh, furdled gruntbuggly!
In destructor.

wd=C:\RHE\src\test
%auto_ptr-test 17
In parameterized constructor.
terminate called after throwing an instance of 'i'
Abort!
Exiting due to signal SIGABRT
Raised at eip=0001648e
eax=006dfe6c ebx=00000120 ecx=00000000 edx=00000000 esi=00000000 edi=006dffc4
ebp=006dff18 esp=006dfe68 program=C:\BIN-TEST\AUTO_P~1.EXE
cs: sel=01a7 base=01680000 limit=006effff
ds: sel=01af base=01680000 limit=006effff
es: sel=01af base=01680000 limit=006effff
fs: sel=017f base=0000e150 limit=0000ffff
gs: sel=01bf base=00000000 limit=0010ffff
ss: sel=01af base=01680000 limit=006effff
App stack: [006e0000..00660000] Exceptn stack: [000538c8..00051988]

Call frame traceback EIPs:
0x000163b4
0x0001648e
0x0001335b
0x00009d6b
0x00005338
0x00005362
0x00001e51
0x000016a3
0x00012ab8

wd=C:\RHE\src\test
%


(Interestingly enough, the destructor IS called if I enclose
most of the body of main() in a try block, just like 15.2
says.)

So either Lippman's right, and my compiler is busted... or I'm
misunderstanding something... or the concept that local objects
in a function are always destructed on exception is just wrong.

Anyone here have further knowlege/experience with this matter?


Cheers,
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
 
A

Alf P. Steinbach

* Robbie Hatley:
I've been playing with "auto_ptr" and the "Resource Acquisition
Is Initialization" concept. On page 199 of Lippman's book
"Effective C++" he says "All active local class objects of a
function are guaranteed to have their destructors applied
before termination of the function by the exception handling
mechanism.".

Note that if the exception is never caught the function is not terminated by
the exception _handling_ mechanism, but rather by an automatic call to (I
think it was) std::terminate. Which in that case doesn't clean up, since its
job is to terminate the program, guaranteed. Second, note the word "active",
which as I read it implies "successfully constructed". Third, the sentence
should be parsed as "local (class objects)", not "(local class) objects".
Presumably nobody makes that error, but it would have been more clear to write
e.g. "All successfully constructed local objects of class type..." -- IMHO.

Btw., the first point is what causes your example program to terminate without
cleaning up.

Add a try-catch in 'main' and you'll get cleanup, or alternatively or
additionally, try out calls to std::terminate, std::exit and std::abort to
check the cleanup (or rather, the lack of cleanup) behavior.
 
R

Robbie Hatley

Alf P. Steinbach said:
* Robbie Hatley:

Note that if the exception is never caught the function is not terminated by
the exception _handling_ mechanism, but rather by an automatic call to (I
think it was) std::terminate. Which in that case doesn't clean up, since its
job is to terminate the program, guaranteed.

Then Lippman's sentence, as written, is incorrect. To make it
a true statement, he'd have to add the following clause to the end:
", provided that the exception-handling mechanism ACTUALLY IS INVOKED."
Second, note the word "active", which as I read it implies
"successfully constructed".

Yep, ISO14882 sec 15.2 does specify that only objects that are
fully constructed, and in try blocks, will be destructed on
exception.
Third, the sentence should be parsed as "local (class objects)",
not "(local class) objects".

Can you define a class "locally"? (Ie, in a function?) I didn't
think that was possible.

#include <iostream>

double Glunk()
{
class Smatz
{
public:
double Glurtz;
};
Smatz Catz;
Catz.Glurtz = 17.4;
return Catz.Glurtz;
}

int main()
{
std::cout << Glunk() << std::endl;
return 0;
}

Holy cat crap, Batman, that actually compiles and runs!
I didn't even know you could do that.
Presumably nobody makes that error, but it would have been more clear to write
e.g. "All successfully constructed local objects of class type..." -- IMHO.

Yah, that, and a warning about the objects having to be in a try block.
Otherwise, the standard doesn't seem to guarantee they'll be destructed
on exception.
Btw., the first point is what causes your example program to terminate without
cleaning up.
Yep.

Add a try-catch in 'main' and you'll get cleanup

Did that. Yep, it destructs my Vogon. Wait, that's backwards...
the Vogons are supposed to BE destructors. Never mind, it's getting
late, my humor's getting weird.
or alternatively or additionally, try out calls to std::terminate,
std::exit and std::abort to check the cleanup (or rather, the lack
of cleanup) behavior.

Good idea. I'll try playing with those in conjunction with objects
to see when the destructors [are | are not] invoked.

RESISTANCE IS FUTILE! YOU WILL BE DESTRUCTED!

Cheers,
Robbie Hatley
Tustin, CA, USA
email: lonewolfintj at pacbell dot net
web: home dot pacbell dot net slant earnur slant
 
G

Greg

Robbie said:
I've been playing with "auto_ptr" and the "Resource Acquisition
Is Initialization" concept. On page 199 of Lippman's book
"Effective C++" he says "All active local class objects of a
function are guaranteed to have their destructors applied
before termination of the function by the exception handling
mechanism.".

I don't think that's true, though. The standard doesn't seem
to require it. Section 15.2 just says that all objects
constructed SINCE ENTERING A TRY BLOCK will be destructed
on transfer of control to a catch block. That's very different
from Lippman's statement.


(Interestingly enough, the destructor IS called if I enclose
most of the body of main() in a try block, just like 15.2
says.)

So either Lippman's right, and my compiler is busted... or I'm
misunderstanding something... or the concept that local objects
in a function are always destructed on exception is just wrong.

Anyone here have further knowlege/experience with this matter?

Local objeccts are destroyed when they are no longer in scope. A thrown
exception caught in one scope will destroy all local objects in the
scopes that lie between it and the point where the exception was
thrown. This process is called "unwinding the stack".

If the exception is not caught or there is some other problem that
prevents execution from resuming within an enclosing scope of the
thrown exception, then the local objects tehnically (at least) remain
in scope and are not destroyed.

Greg
 
G

Greg

Robbie said:
Then Lippman's sentence, as written, is incorrect. To make it
a true statement, he'd have to add the following clause to the end:
", provided that the exception-handling mechanism ACTUALLY IS INVOKED."

I forgot to weigh in on the "Lippman controversy" in my earlier post.

Lippman's statement is accurate. In the event of an uncaught exception
or other fatal error, the exception handler does not terminate (that
is, exit) the function. In this case the function does not return
before the program itself aborts execution.

Greg
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top