C++ exceptions can be an optimization

I found this thread (http://forums.pcsx2.net/Thread-blog-C-exceptions-can-be-an-optimization) some time ago, it's a bit old now, but i was wondering what the c++ "gurus" here think about it?
I've not used exceptions much, but i think i understand and agree with what is said. On the same subject, I generally find articles on the web (and in the c++ books i have read for now) about how to make exception code compile and work, but never how to properly use them. DO you guys have some good litterature about exceptions to advise?
I know I've answered this question several times, but a quick search did not find the full-fledged answer I was looking for. However, there is this response which gives a little detail.

http://www.cplusplus.com/forum/general/19505/

C++ Coding Standards (Sutter/Alexandrescu) also talks about when to use exceptions.

I agree with the article under the assumption that the failure scenario occurs very infrequently with respect to the number of iterations.
Thanks for the answer, but that's not exactly what i meant about how to use exceptions properly. I know what is in this post already. What i mean is if there is any particular position in the code to use exceptions well. For example, is it recommanded to catch everything, or to catch specific exception in a same catch block. Or should all exceptions be catched at the most upper level possible with a generic handling, or at specfic positions with specific handling? To make it simple, is there a strategy to use exceptions, the same way we choose a STL container based on what we need to do with our data for example?
That's what i never find in documentation
I'm not a guru, but I have used exceptions quite a bit in restricted circumstances...

Before I go on, this post might be of interest to you, if you haven't already seen it:
http://stackoverflow.com/questions/242587/exception-handling-architecture

Or rather, the disagreeing posts it links to (by Joel and Ned Batchelder). It's the debate which makes the posts interesting, esp. given Joel's reputation.

I think that designing and implementing a good, overarching exception architecture is difficult. And it only works if applied consistently. But there are places where it makes good sense to use them.

Taking as read what jsmith and the C++ Coding Standard book say (you said you know that side of exception handling...)

Exceptions should be caught and handled as early as it possible to handle them gracefully. If you cannot handle them, you should leave them to be handled at another level.

In some cases you might catch an exception and only then realise you can't handle it. In this case you should rethrow it. I also used catch-rethrow in debug builds from time to time, using additional macro-ed handlers, to trace the path of an exception (they just catch, log, rethrow).

It also follows that you should only catch specific types, as you are only catching the ones you can handle. The exact details does, however, depend on the exception hierarchy.

To minimise the number of handlers I require, I don't code a new type of exception for every specific error. I code one for every category of error (see below for an example).

Places where I use exception handling are:

1. When normal error handling would get very messy.

For example, in an expression evaluator. The code is complicated enough without error checks, so throwing out of the code at all levels makes sense. In this case I would

(a) wrap the whole evaluation in a single try-catch block, and (b) prob. use a single type of exception -- expr_eval_error -- which takes an error code and enough other info to identify what was going wrong with the evaluation when it was thrown.

If other exceptions could occur, like out of memory, then I would catch then as well. But only if I could so somethine about it.

In other similar circumstances, where the code complexity is high enough to merit it, I might throw and catch exceptions at different levels. This is usually heavily algorithmic code.

2. To wrap calls to 3rd party code: this is one of the two places I would use catch-all.

3. The other place for catch-all is to protect the application's main function/message loop.

If an unknown exception type is caught, the application should gracefully shutdown, after saving the user's data, as its state will no longer be known. So there is no need for catch-all at any other level. The only reason to catch the third parties errors, rather than letting them propogate to the top most handler, is an extra error logging opportunity (to apportion blame!)

The use of catch all can be esp evil if used in the wrong place, as it can hide errors. It can be useful to add this kind of exception handling (temporarily and at tight scope) for diagnostic puprose, but I would never check it into the source control system!

I do not generally use exception handling in code which is not speed ciritical. This includes the message handlers in WIN32 message loops and other equivalent functions.

I also don't use exception handling in code where I am using a lot of (e.g. WIN32) API calls which force me to use error codes. A mish-mash of approaches just confuses things! (Well, it does me!!)

It is also a bad idea to throw exceptions between DLLs (and I presume shared-objects).

As the top level objects (in the object model) are the ones communicating between modules, I tend to use return codes for their error reporting. Exception handling is restricted to their subcomponents and to smaller utilities. And this is what STL is using anyway.

As I said at the start, if a good exception architecture exists, and everyone uses it consistently, then it can be very good, In parctice I stick to the kind of limited use I mentioned above.

If you are interested in reading detailed discussions, I suggest you google for "exception handling patterns" and also "exception handling anti-patterns".

Andy

P.S. The post you referred to isn't that old. Exception handling techniques aren't evolving esp. fast!
Last edited on
Thanks a lot, that's the kind of answer i hoped for!
Another place where exceptions work well is when overloading operators.
Recently, I had to beautify uses of SQLite:
DB <<"select column1 from table where column2=? limit 1;"<<value1<<Step()>>value2;
Without exceptions, there's no way to check for error conditions. At least, not without breaking the code up in pieces, which would defeat the purpose of using operators.
Exceptions should be caught and handled as early as it possible to handle them gracefully
I do the opposite but I think that's OK for critical errors (array index out of bounds, read/write file errors)

It is also a bad idea to throw exceptions between DLLs (and I presume shared-objects)
Why? I don't have any problems with that.
When the stack is unwound to find an appropriate handler for an exception, some comparison has to be made of the type of object thrown vs. what can be caught. This is implemented via RTTI. The internals of RTTI are not standardized meaning that exceptions that cross the library/DLL boundary may not be caught when they were intended to.

This can happen not just if the library was compiled with a different compiler than the application, but even if the library was compiled with a different version of the same compiler as the application.

@Null -- I am unclear about what you mean by catching an exception as late as possible.

By "as soon as possible" I mean as soon as possible to do something about the condition that resulted in the exception being thrown, so normal function can be resumed. I do not mean just catching the exception as early as possible.

I'm left wondering under what conditions it would be better to wait longer to return to normal operation?

The reason for avoiding exceptions between DLLs is as jsmith stated.

There are always exceptions to a rule, so you might decide that it's ok for a particular dll and exe to work with the same excceptions. But you then you have to treat the modules as a matched set, which is not a good idea for a dll which might be useful in other circustances later on.

(For the same reasons I tend to be very wary of using C++ linkage, esp. exporting whole classes; due to name mangling and memory allocator issues).

Aside

I have to admit that I find code like

DB <<"select column1 from table where column2=? limit 1;"<<value1<<Step()>>value2;

a bit disquieting.

Firstly, it breaks the "Preserve Natural Semantics For Overloaded Operators", as (also) started in C++ Coding Standards (Sutter/Alexandrescu). The string "select ..." is not being inserted into DB, not is DB being left-shifted

Secondly, it looks to me like operator<< is working on different levels in the same line, unlike its usual behaviour (value1 is inserted into/appeanded to the query, the query is inserted intot he database, ...).

Thirdly, the object responsibilites are unclear. In object oriented database APIs, I generally expect to see distinct query, parameter, and result objects.
Last edited on
Yes, but it's terse, safe, and efficient. The point was to minimize typing and boilerplate code while gaining safety without adding overhead, not winning an award to the nicest-looking code. If you know what the wrapper does -- and it's short enough to be fully understandable in a couple minutes -- I can assure you you'll find that line a lot quicker to understand than the interface it wraps.
I haven't looked at SQLite, so cannot make that judgement. But the line does look a bit too busy/terse for me. But I do realise that you are not alone with your opinion.

A quick google later and I found SOCI, which use operator<< in a similar way:
http://soci.sourceforge.net/

And this one, which is more to my taste:
http://code.google.com/p/sqlite3pp/wiki/UsagePage
Then allow me to demonstrate.
Let's say you want to get all rows from a table where a string column matches a certain value, and each row contains an int, a Unicode string, and a blob. With my code, that's
1
2
3
4
5
6
7
8
9
10
11
12
const char *stmt_string="select int_column, str_column2, blob_column from table where another_str_column=?;";
{
    Statement s(DB <<stmt_string);
    s <<a_wstring;
    while (s.step()==SQLITE_ROW){
        int i;
        std::wstring string;
        std::vector<unsigned char> blob;
        s >>i>>string>>blob;
        //...
    }
}

With SQLite, it becomes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
sqlite3_stmt statement;
//Yay! Magic numbers!
sqlite3_prepare_v2(DB,stmt_string,-1,&statement,0);
std::string converted=w2utf8(a_wstring);
//Note: 1-based indexing of parameters.
sqlite3_bind_text(statement,1,converted.c_str(),converted.size(),-1);
while (sqlite3_step(statement)==SQLITE_ROW){
    int i;
    std::wstring string;
    std::vector<unsigned char> blob;
    
    //Note: 0-based indexing of results.
    i=sqlite3_column_int(statement,0);
    string=utf82w((const char *)sqlite3_column_text(statement,1));
    //Needs to be called first for type coercion.
    sqlite3_column_blob(statement,2);
    blob.resize(sqlite3_column_bytes(statement,2));
    memcpy(&blob[0],sqlite3_column_blob(statement,2),blob.size());
    
    //...
}
sqlite3_finalize(statement);
And I didn't even include error handling code.

EDIT: My post may sound overly critical of SQLite, but just let me say that I do love it. It has its quirks (the inconsistent indexing schemes being the worst of all, IMO), but it's not like a pure C library could do a lot better.
Last edited on
Topic archived. No new replies allowed.