Sign in to follow this  
dave

Does anyone here intentionally write 'Exception Strong' and 'Exception Neutral' code?

Recommended Posts

I'm interested in ur answer to the title of this thread. I recently bought Exceptional C++ by Herb Sutter and it's a great book. A Huge chunk of it is dedicated to writing such code and it appears as though i naturally write this code. I'm the first to admit i've have a hell of alot to learn still so there are probably loads of you out there who can shed light on what Herb is getting at. It appears as though this code quality is nothing much more than: -making sure you don't pass-by-value except when strictly needing to -making sure ur destructors don't throw -making sure that if an exception does occur in a function, that u let it propogate out of the function leaving the state of the code in a healthy state. Now granted i havn't read all of that section yet, most of it though, but when i came back to my code i noticed that it all appears pretty strong. Although he does seem to highlight alot of thing to do with exception safe writing that appear obvious. The first being that you dont handle the exceptions in templated code because obviously you dont know the type, well you dont. Another being that you have to assume things about non-standard objects. Like assuming the destructors don't throw. I fully understand his use of auto_ptr myself. Can anyone who has this book, or knows what i'm talking about regardless, please enlighten me to the general concept of this style of code in their own words. And also, i know it is alot to ask but is anyone willing to knock up any examples that come to mind regarding what is 'Exception strong/neutral" code and what isnt. Some of Herbs examples are a bit densly coded and explained for my liking. Thanks in advance for any replies. ace

Share this post


Link to post
Share on other sites
Quote:
Original post by ace_lovegrove
It appears as though this code quality is nothing much more than...


1) This doesn't have a lot to do with exception safety, it's more about common sense and avoiding spurious copies of objects.
2) Destructors shouldn't throw. Ever. Full Stop. This isn't really a key factor in exception safety, it's just something that needs to be done by default.

Note that if your destructor potentially throws, refactor the code into a throwing close or shutdown function, and then surround it in the destructor with the appropriate try block. In normal circumstances a developer will call close before shutdown, but if they forget or stack unwinding is triggered the destructor will still run safely.

3) maybe, maybe not, it depends on the type of guarantee that the function offers, if it's nothrow then this isn't acceptable at all.

Although these are a good starting point, they aren't nearly enough to be confident. Finish reading the book, try some of the examples and see how hard it really is to write exception safe code in real world environments - especially if you consider that ever statement and function call can possibly throw, including new.

Exception safety analysis is even harder to perform - and as most of the examples demonstrate in some cases good code isn't enough on it's own, the design has to be solid to support exception safety (see the example on the design of a stack class). One of the key factors in reviewing how I wrote code was the example on the number of code paths through a function if anything could throw - it's heart breaking to realise how much code doesn't even provide the basic guarantee.

Exception-Safety in Generic Components by Dave Abrahams covers similar ground to Sutter, and is in fact the original source of the guarantee names (strong, nothrow and basic). Once you learn what the guarantees are you also need to know when it is appropriate to use each of them, and when optimization (or project deadlines) will force changes to this.

Other things to consider may be:
- anything can throw, including new (this encourages the use of smart pointers and STL containers)
- avoid the use of try ... catch blocks, allow exceptions to be caught by clients of the code.
- use good design techniques to simplify functions (1 responsibility per function) to allow you to offer the tightest guarantee you can.
- functional interfaces that have side effects that need to be undone in exceptional circumstances need to be wrapped in objects that are allocated on the stack (this can introduce a significant ammount of small classes)
- exception safety should be built into code as a first priority in the same way that security is.
- don't let exceptions escape module boundaries (.dll's)

Share this post


Link to post
Share on other sites
Basically, there are 4 guarantees a function can give with regards to exceptions:

1.) The no guarantee
The most evil and most prevalent; if your code throws an exception, it's anybody's guess as to how the program is going to behave

2.) Weak guarantee
If the function throws an exception, the program will be in a valid, though not neccesarily predictable state

3.) Strong guarantee
If the function throws an exception, the program will be in the same state as when it entered the function. This is also know as 'commit-or-rollback' semantics; either the entire function succeeds, or everything it does is rolled back.

4.) The no throw gaurantee
Obvious; the function never throws/fails. Ever.

Addressing the points you raised:

-making sure you don't pass-by-value except when strictly needed
Not neccesarily, I think it depends. Writing code that gives the strong guarantee isn't made that much more complicated by pass-by-value semantics.

-making sure your destructors don't throw
This is just exception safety 101. If a destructor throws when it is invoked as the result of a stack winding caused by another exception being thrown, your program will simply terminate. And there are some other subtleties caused by throwing destructors, but that's the big one.

-yadda yadda yadda
This is 'exception neutral'. A function is neutral if it simply allows exceptions to propogate out of it. This is somewhat preferred if your function can give the strong guarantee, as then the state of the program is known all the way up the call tree.


Yes, std::auto_ptr is extremely useful in writing exception safe code, just be wary of its nuances.

As Sutter states, the real trick to writing exception safe code is to do all the work that can fail off to the side, and then update the actual program state using only nothrow operations (such as Swaps).

Andrei Alexandrescu wrote a really good article on the subject of writing exception safe code (and provided a nice little helper utility for it)
http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/

Share this post


Link to post
Share on other sites
Ones of the keys to writing exception safe code is isolating operations that can throw from operations that can't. I don't believe Sutter ever actually comes out and says this, but he does provide the greatest example of it ever: The swap idiom. An exception-safe operator= for class C can be implemented like so:


template <typename T>
const C& operator=(const T& rhs)
{
this->swap(C(rhs));
return *this;
}


Yes, I actually write a templated operator=. For just about everything. It only works if C has a constructor taking type T, so it generally just replaces a constructor/operator= pair anyhow.

The point is that the part that can throw (the constructor) is seperate from the part that changes state (the swap function). And the part that changes state can't actually throw. If the constructor throws, the swap function is never called, and the objects state remains unchanged.

The idea that anything can throw at any time is a fallacy. In order for code to throw, something has to fail. In order to fail, code has to be manipulating some resource: Allocating memory, freeing memory, aquiring system resources, talking to device drivers, etc. Naturally, you can't do much if you don't use these resources. For instance, if an assignment between two primitives (That is; just copying bits around in memory) fails, there is something going horribly wrong and your computer is likely to explode any second.

Share this post


Link to post
Share on other sites
Exception neutral code generally refers to code that doesnt throw or catch exceptions on its own, hence its neutralness/indifference towards exceptions. It does however clean up after itsef in an exception friendly manner, ie. use auto_ptr/CComPtr for memory, cstr's allocate all resources and dstr's free them.

Exception Strong code does all of htat but also know how to properly throw and catch exceptions.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this