Exception Specifications

closed account (3hM2Nwbp)
I've read an article from Herb Sutter that pretty much can be boiled down into:
GotW wrote:

Q) When is it worth it to write exception specifications on functions? Why would you choose to write one, or why not?

A) In brief, don't bother. Even experts don't bother.

source @ http://www.gotw.ca/gotw/082.htm


He then goes on to say that throw specifiers can lead to performance penalties by not making methods with throw specifiers inline.

Up til now, I've always marked my nothrow methods like so, if it could guarantee a nothrow, and marked methods that are clearly exceptional as such:

1
2
3
4
5
6
7
class c
{
    // Will Not Throw
    void someFunction(void) throw();
    // May throw
    void someFunction2(int index) throw(IndexOutOfBoundsException);
};


What are your habits when it comes to exception specifiers?

*Edit - Oh and would it make sense to mark a pure virtual method as a no-throw? I'm not sure how that would work out...would it force the overrides to also be no-throw?
Last edited on
What are your habits when it comes to exception specifiers?


I don't bother. It's does nothing but hinder maintainability, IMO.

*Edit - Oh and would it make sense to mark a pure virtual method as a no-throw? I'm not sure how that would work out...would it force the overrides to also be no-throw?


AFAIK it's part of the function signature, so yeah if a pure virtual is no-throw, any implementations of that function must also be no-throw.

But I'm not 100% on that.
+255 Disch.

(and yes, you're right Disch).
Luc Lieber wrote:
What are your habits when it comes to exception specifiers?

duck and cover

now seriously

there's one question behind that exception nonsense: Can't someone else do it? And I think the answer is: the garbageman can. Or was it the garbage collector (that would fit)?
I have not practiced with those ever. But here is what I have been taught in various courses.

When you design function that returns error codes, they are part of your function's contract. The client has to be aware of them and must revise its code if this contract changes. Exceptions were designed to be part of a system-wide contract, not individual specification of some function.

Exception specifications are designed to mark NOT what you can throw, but to provide very stringent guarantee that you throw very little (usually nothing). In practice, this is hard to fulfill and maintain unless your function's implementation is self contained and uses no supporting functions (that may throw anything), or uses only no-throw functions. Another important point is, not to use catch all clauses just to ensure that you meet the exception specification, because this suppresses the entire mechanism.

Regarding the override, the overrider must have not less restrictive exception specification (one that does not allow more exceptions to be thrown.) Same applies to function pointers with exception specification. No exception specification means - "can throw anything".

Also, if you throw exception that is not in your exception specification, the code will terminate without unwinding the stack. The only way (I know) that can circumvent this is to use custom unexpected handler and bad_exception is the specification.
http://www.cplusplus.com/reference/std/exception/unexpected/
http://www.cplusplus.com/reference/std/exception/bad_exception/

Other than maintainability and the fact that the stack does not get unwound in case that you throw invalid exception, why are exception specifications so notoriously hated? I mean, seriously, why?

Regards
Other than maintainability and the fact that the stack does not get unwound in case that you throw invalid exception, why are exception specifications so notoriously hated? I mean, seriously, why?


Those 2 reasons aren't enough? They're pretty major.

I find the whole thing with having to have a special case for unexpected exceptions, in particular, to be redundant. Exceptions are the special case -- that's the whole point. Having a special case for the special case is just absurd.

Really exception specifications just add more complexities to the code. And for what? As far as I can see there's no worthwhile benefit. If anything there are even more hinderances attached (as explained in previous posts, using them might even have worse performance than not using them).
They are an absolute maintenance headache for very little, if any, benefit.

Sure, it's easy to write an exception specification for foo() if it doesn't call any other functions. But as soon as it calls bar(), foo() has to be updated to either handle all exceptions that bar() can throw, or add bar()'s exception specifications to foo()'s exception specification list. And the problem just ripples up from there.

Besides -- every function that uses any STL container automatically has std::bad_alloc in its exception specification, and possibly even others (std::range_error, etc) depending on the container used. Indeed, every function that uses new has std::bad_alloc in its exception specification.

For what benefit? For some promise that the compiler may be able to generate more optimal code. Emphasis on may because in practice compiler writers didn't/couldn't provide any better code.


I think that people treat exception specifications as specification of exceptions. Like the way that the function prototypes and the object's syntactical interface are sometimes treated as the contract and interface specification.

Indeed, there is no point in recursively embedding exceptions from the supporting functions in the specification of the caller. This is not maintainable. But if I have indexing function like vector::at, which is entirely self-contained and only performs a simple range check, then I can announce throw(std::out_of_range). Nothing else will be thrown, because I am the only one who can throw something.

Of course, nothing is gained by just specifying throw(std::out_of_range). Without knowing the conditions when I throw the exception, the client has no use for it. The same is true for argument and return types. Say, with pointer to function int (int, int), wouldn't it matter if it is addition or division operation, whether it is monotonous in each argument, whether it works outside of some finite range, etc. The type is not the entire contract, it is just the part of the contract that can be enforced by the compiler.

There are some subtleties. For example:
1
2
for(int i = 0; i < (int)v.size(); ++i)
  sum += v.at(i);
Now I may want to declare this code nothrow. But, what if vector::at contains a buffer overrun (weird, I know). Then my index may change unexpectedly to some arbitrary value and vector::at will throw the exception. However, although it is debatable, IMO the out_of_range exception would be vague anyway.

As I said, stack unwinding can be fixed with std::bad_exception and custom unexpected handler. So the clean-up problem is not really a problem, or is it?

Without the nothrow specifications, how would one implement strong exception guarantees? Regarding the performance, I actually read from the web that nothrow specifications sometimes result in better optimizations and there will be a substitute keyword in C++0x, despite that other exception specifications will be generally deprecated. Even if there are penalties, I wonder if they concern the normal program flow in the absence of exceptions. My question is, why is the feature going to be deprecated? (I can't settle the issue in my head and I just don't like to have unresolved issues like this.)

Regards

EDIT: I think I am looking at this the wrong way. The working group probably just wants to tidy their language a bit. I still think that the feature is partly blamed due to misuse. I mean, like using pointers non-portably.

EDIT 2: To state again, I don't think anyone should use exception specifications to decorate every function they have. But some methods are supposed to be minimal and self-contained by design, and consequently can meet stronger requirements without fuzz. It allows the caller to direct their effort in implementing transaction semantics. Even for a method that throws, if I am absolutely certain that there are only exceptions under conditions that are impossible in my code, then I can assume no multi-level returns.
Last edited on
how would one implement strong exception guarantees?
The point is there are no strong exception guarantees in C++. Remember, you can have C functions (and whatever else) in C++ and the so called guarantees simply don't apply to other languages.
The point is there are no strong exception guarantees in C++.
Why? Look at this: http://www2.research.att.com/~bs/3rd_safe0.html. Most STL operations provide exception guarantee at least as strong as the operations of the user types they host.

It isn't that hard to achieve strong exception guarantee:
Achieving the strong guarantee requires partitioning the steps of an operation into two categories:

1. Operations that may throw, but don’t do anything irreversible
2. Operations that may be irreversible, but don’t throw.

As long as we can break everything into those two categories, and everything in category 1 happens before everything in category 2, we’re home free.
The original article can be found here: http://cpp-next.com/archive/2009/10/exceptionally-moving/

Besides simply using throw(), I don't think there is anything conceptually wrong or retrograde with declaring the exceptions of operations that should be simple by design. If you are declaring this in an abstract base class, it will at least inform the implementer that the client expects simple self-contained implementation with less external dependencies. Of course, this is not desirable for some render() or getInitializationInfo() or smth method. It's not one size fits all.

Regards
Last edited on
Look at this
The link is broken.

Most STL operations provide exception guarantee at least as strong as the operations of the user types they host.
What does this tell you about strong exception guarantees?

It isn't that hard to achieve strong exception guarantee
Aren't you forgetting not calling into languages that don't implement exceptions? This is not a Java environment where there's one way, the Java way. C++ is designed to integrate with a C and possibly Fortran environment; it's a tool for building libraries and applications. The one horse race rules simply don't apply.

Besides simply using throw(), I don't think there is anything conceptually wrong or retrograde with declaring the exceptions of operations that should be simple by design.
Maybe that's because you've not had to maintain such code.
kbw wrote:
The link is broken.

The link does not work because of the trailing period :)
Here it is again: http://www2.research.att.com/~bs/3rd_safe0.html

What does this tell you about strong exception guarantees?
It tells me that genericity has its set of unique problems. But the promises are very reasonable and could not be improved. I wish code was written so well, don't you?

Aren't you forgetting not calling into languages that don't implement exceptions?
You want the entire system to have strong exception guarantee. Focusing on the weakest link in the chain will make you agnostic to methodical improvement. And actually, the lack of exceptions makes the work easier (even if bulkier), because the rollback is harder to mess up if you want it.

Maybe that's because you've not had to maintain such code.
I can tell you that's true, because I have only had to maintain C code. But I wouldn't use it as example of C programming either.

In fact, I meet with anti-practices and poorly written code. Do you tell me that the code you have to maintain causes you pain, because of a language feature? Are you sure that the people who produced the code had designed it thoughtfully, premeditating the design?

Or are you arguing that people can use exception specifications to write junk that is hard to maintain? And that time constraints prohibit such meticulous design in practice? If that is what you say, point taken, but I would hardly use that as argument against some language feature.

Regards
Here it is again: http://www2.research.att.com/~bs/3rd_safe0.html
It turns out that's just a link to one of his books, which I just happened to still have in Safari Books. He's just talking about STL containers, not the general case.

It tells me that genericity has its set of unique problems. But the promises are very reasonable and could not be improved. I wish code was written so well, don't you?
I don't know what that means.

Do you tell me that the code you have to maintain causes you pain, because of a language feature?
The inappropriate use of language features is always a pain.
Last edited on
No biggie.

I said already in my first post that exceptions were never designed to be part of particular function's contract, but to be part of a system-wide contract. I thought that exclusively for self-contained functions (that call no other function), specifying the exceptions that they throw and the conditions under which they are thrown would be ok and maintainable. I didn't mean that every function should be decorated with them, as I believe is the case with poorly written code. I speculated, that the occasional hint from exception specification of such small self-contained function could make implementing the error recovery of its clients easier (with strong exception guarantees or whatever method you prefer). And IMO exception handling is all about error recovery, right?

But, 1st, probably noone cares much about graceful recovery in practice. I've seen in C error logging and sub-system reset, which is the most primitive form of "recovery". And, 2nd, I am in doubt if exception specifications are useful language utility. They can be validated in pointers and overrides, which I like, but not much else.

I'll settle this in my head over time. Thanks for the answers. It's my issue now. :)

Regards

EDIT: If anyone wants to assist the OP, please ignore the last few posts and go for it. I didn't imagine that my question would end up occupying this thread so blatantly. :(
Last edited on
Topic archived. No new replies allowed.