Exception handling the right way

  • Thread starter Bart Friederichs
  • Start date
B

Bart Friederichs

Hi,

I was just browsing the C++ FAQ and stumbled upon the 'mind sets' that
are wrong for using C++ exception handling. I am looking for the 'right'
mind set. I come from a C background, and still use a lot of C style
programming in my C++ programs. Exception handling is one of the things
I never extensively used; with my C-return-codes-mindset I'd put too
many exception handling code in my programs.

Are there any good examples of projects that use it correctly? (As the
FAQ states you should have a system-wide perspective, simple exception
howto's are not really useful).

Bart
 
A

anon

Bart said:
Hi,

I was just browsing the C++ FAQ and stumbled upon the 'mind sets' that
are wrong for using C++ exception handling. I am looking for the 'right'
mind set. I come from a C background, and still use a lot of C style
programming in my C++ programs. Exception handling is one of the things
I never extensively used; with my C-return-codes-mindset I'd put too
many exception handling code in my programs.

What do you mean under "too many exception handling code" ?

You should handle an exception at the point when you know how to resolve
the error.
Are there any good examples of projects that use it correctly? (As the
FAQ states you should have a system-wide perspective, simple exception
howto's are not really useful).

I like this explanation:
http://www.boost.org/community/error_handling.html
 
C

Chris M. Thomasson

Bart Friederichs said:
Hi,

I was just browsing the C++ FAQ and stumbled upon the 'mind sets' that
are wrong for using C++ exception handling. I am looking for the 'right'
mind set. I come from a C background, and still use a lot of C style
programming in my C++ programs. Exception handling is one of the things
I never extensively used; with my C-return-codes-mindset I'd put too
many exception handling code in my programs.

Are there any good examples of projects that use it correctly? (As the
FAQ states you should have a system-wide perspective, simple exception
howto's are not really useful).

Take a look at this first:

http://www.ddj.com/cpp/184403758
 
B

Bart Friederichs

anon said:

Thanks for the pointers, and I started a little experimenting. Soon I
ran into this problem:

int main () {
A *a; B *b; C *c;
try {
a = new A();
b = new B();
c = new C();
} catch (...) {
delete a;
delete b;
delete c;
}

return 0;
}

Which results in a runtime error when B's contructor throws an
exception. How to correctly free resources on the heap in exception
handling?

Bart
 
C

Chris M. Thomasson

Bart Friederichs said:
Thanks for the pointers, and I started a little experimenting. Soon I
ran into this problem:

int main () {
A *a; B *b; C *c;
try {
a = new A();
b = new B();
c = new C();
} catch (...) {
delete a;
delete b;
delete c;
}

return 0;
}

there are some errors here... Simple fix:


int main() {
A* a = NULL;
B* b = NULL;
C* c = NULL;
try {
a = new A;
b = new B;
c = new C;
} catch(...) {
delete a;
delete b;
delete c;
}
return 0;
}



or, even better:


int main() {
std::auto_ptr<A> a(new A);
std::auto_ptr<B> b(new B);
std::auto_ptr<C> c(new C);
return 0;
}
 
C

Chris M. Thomasson

Chris M. Thomasson said:
there are some errors here... Simple fix:


int main() {
A* a = NULL;
B* b = NULL;
C* c = NULL;
try {
a = new A;
b = new B;
c = new C;
} catch(...) {
delete a;
delete b;
delete c;
}
return 0;
}


Ummm... Well, I forgot to destroy the pointers in the case of no
exception!!! You could do this:

int main() {
A* a = NULL;
B* b = NULL;
C* c = NULL;
try {
a = new A;
b = new B;
c = new C;
} catch(...) {
}
delete a;
delete b;
delete c;
return 0;
}


Man, that looks like total crap when compared to the version which makes use
of smart pointers...


OUCH!

;^(
 
B

Bart Friederichs

Chris said:
int main() {
std::auto_ptr<A> a(new A);
std::auto_ptr<B> b(new B);
std::auto_ptr<C> c(new C);
return 0;
}

This terminates when B() throws, simply adding the try-catch around it
seems to fix that.

Learned again something; the smart pointers.

Bart
 
N

Nick Keighley

This terminates when B() throws, simply adding the try-catch around it
seems to fix that.

the whole point is to avoid a try-catch! What do you mean it
terminates? The program will terminate whether new B throws or not.
Learned again something; the smart pointers.

try putting print statements in the CTOR and DTOR
of A, B and C and you should be able to work out
what's going on.
 
J

Jorgen Grahn

Thanks for the pointers, and I started a little experimenting. Soon I
ran into this problem:

int main () {
A *a; B *b; C *c;
try {
a = new A();
b = new B();
c = new C();
} catch (...) {
delete a;
delete b;
delete c;
}

return 0;
}

Which results in a runtime error when B's contructor throws an
exception. How to correctly free resources on the heap in exception
handling?

Usually you can side-step this.

int main()
{
A a;
B b;
C c;
exit 0;
}

Or if there is some extraordinary reason you have to new them, maybe
their lifetime fits into an object? I find this is often the case.

class MeaningfulSomething {
public:
MeaningfulSomething(args)
: a_(new A()),
b_(new B()),
c_(new C())
{}
~MeaningfulSomething() { delete ... }
A * const a_;
B * const b_;
C * const c_;
};

/Jorgen
 
J

James Kanze

This terminates when B() throws, simply adding the try-catch
around it seems to fix that.
[/QUOTE]
the whole point is to avoid a try-catch!

There's no point in using exceptions if you don't have a
try/catch somewhere. Typically, the main function is the place,
at least in single threaded applications.
What do you mean it terminates? The program will terminate
whether new B throws or not.

But it will not terminate in the same manner.
 
J

James Kanze

class MeaningfulSomething {
public:
MeaningfulSomething(args)
: a_(new A()),
b_(new B()),
c_(new C())
{}
~MeaningfulSomething() { delete ... }
A * const a_;
B * const b_;
C * const c_;
};

This will leak memory if any of the new expressions throws.
 
B

Bart Friederichs

Yannick said:
Don't get me wrong, I really respect the writings of Alexandrescu as
well he has brought to the C++ community. However, I have serious
doubts about recommending his writing to a beginner that is trying to
figure out exceptions. I fear that he would get lost in the
complexity of the details and templates presented in this article (or
in Loki and Mordern C++).

I am not a beginner. I understand the scopeguard completely. I myself
though have serious doubts about the usability of it in our applications
(time critical automation control). I get a slight sense of extra
clutter in my code.

I just never seriously used exception handling, because I never needed
it. I want to figure out now, if I *really* don't need it, or if I am
missing on some useful programming concepts.
In that regard, I would always recommend to read S. Meyer first, then
H. Sutter and once you grasp both of them, you can move to
Alexandrescu. I would never recommend to read them in the opposite
order.

Do you have any links to that S. Meyer and H. Sutter?

Bart
 
A

anon

Bart said:
I am not a beginner. I understand the scopeguard completely. I myself
though have serious doubts about the usability of it in our applications
(time critical automation control). I get a slight sense of extra
clutter in my code.

I just never seriously used exception handling, because I never needed
it. I want to figure out now, if I *really* don't need it, or if I am
missing on some useful programming concepts.

If you are programming in c++, then you are missing very useful
programming concepts.
 
B

Bart Friederichs

Nick said:
the whole point is to avoid a try-catch! What do you mean it
terminates? The program will terminate whether new B throws or not.

without try-catch:

bf@bf-laptop:~/playground$ ./test
A constructed.
B constructed.
terminate called after throwing an instance of 'int'
Aborted

with try-catch:
bf@bf-laptop:~/playground$ ./test
A constructed.
B constructed.
A destroyed.

try putting print statements in the CTOR and DTOR
of A, B and C and you should be able to work out
what's going on.

That is what I did.

Bart
 
B

Bart Friederichs

Yannick said:
Even better: don't use pointers:

int main()
{
A a;
B b;
C c;
return 0;
}

That is not the point. Sometimes it is needed to use pointers. I also
want to know how to handle excpetions in that case correctly.

Slowly I am starting to understand the mindset. And I have the feeling
it is not really useful for our applications, since there are only few
data-objects, but mostly process-objects. All data is managed in an SQL
database (to 'survive' restarts or crashes).
I like Alan Griffiths article "Here be Dragons" as an introduction:
http://www.octopull.demon.co.uk/c++/dragons/

Thanks, I'll read that.

Bart
 
C

Chris M. Thomasson

Yannick Tremblay said:
Hmm, Alexandrescu & Marginean advanced ScopeGuard article...

Don't get me wrong, I really respect the writings of Alexandrescu as
well he has brought to the C++ community. However, I have serious
doubts about recommending his writing to a beginner that is trying to
figure out exceptions. I fear that he would get lost in the
complexity of the details and templates presented in this article (or
in Loki and Mordern C++).
[...]

Of course the beginner would not necessarily "need" to implement the
details. Luckily, they can simply download the source-code from the article
and include the headers in their projects. IMHO, it would be very nice if
the STL had something analogous to ScopeGuard...
 
C

Chris M. Thomasson

Bart Friederichs said:
This terminates when B() throws, simply adding the try-catch around it
seems to fix that.

Learned again something; the smart pointers.

You could do:
________________________________________________________________
int main() {
{
std::auto_ptr<A> a;
std::auto_ptr<B> b;
std::auto_ptr<C> c;

try {
a.reset(new A);
b.reset(new B);
c.reset(new C);
} catch (...) {
[whatever];
}
}

// everything has been "cleaned up"...

return 0;
}

________________________________________________________________
 
M

Michael DOUBEZ

Bart Friederichs a écrit :
I am not a beginner. I understand the scopeguard completely. I myself
though have serious doubts about the usability of it in our applications
(time critical automation control).

Scope guards have the advantage of ensuring that managed elements are
restored/destroyed... when the scope terminates. This makes invariant
checking really easier (whether you use exceptions or not).
I get a slight sense of extra
clutter in my code.

{
scoped_ressource<Foo> bar(ress);

if(is_false)
{
return;//ressource released automaticaly
}

something_else();
}//ressource released automaticaly

is IMO less cluttered than:

{
acquire_ressource(ress);

if(is_false)
{
release_ressource(ress);
return;
}

something_else();

release_ressource(ress);
}

I just never seriously used exception handling, because I never needed
it. I want to figure out now, if I *really* don't need it, or if I am
missing on some useful programming concepts.

C++ exceptions are meant to reduce the amount of explicit error handling
code: operations can be unwind till the point where the error can
handled (i.e. the error doesn't have to be handled locally).

But they come at the price of exception awareness.
Do you have any links to that S. Meyer and H. Sutter?

Herb Sutter:
http://www.gotw.ca/publications/index.htm

The following link can also be of interest to understand the impact on
design:
http://accu.org/index.php/journals/444
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top