Re: Defining undefined, etc., behavior
Bart van Ingen Schenau wrote:
ThosRTanner wrote:
Bart van Ingen Schenau wrote:
The problem with exception specifications for templates is that you
can not know what you should put in the exception specification.
Consider, for example, the following:
// file: template.h
// provided as part of a 3rd party library
template <class T>
T* createDefault() throw(std::bad_alloc /*, and what else? */)
{
return new T();
}
// file my_source.cpp
#include "template.h"
struct A
{
A() throw() {}
};
struct B
{
B() throw(int) {}
};
void foo() throw(std::bad_alloc)
{
A* a = createDefault<A>();
try
{
B* b = createDefault<B>();
}
catch(int)
{
}
}
Assuming a compile-time check of the exception specifications, what
should the exception specification on createDefault<>() have been to
avoid a compiler diagnostic.
With the code as you have written it, there is no way you can do this.
Suggestions that come to mind are:
1) No exception specification (allows anything to be thrown, and
therefore everything must be caught.
Which will effectively mean that the use of exception specifications
will be discouraged, just like the current status quo.
I realise people are lazy. People didn't like the introduction of the
const keyword to C, because if you used it it would force you to write
correct code. But people accept it now without query.
The reason people may be discouraged now is that if you write an
exception specification, and you do something wrong in a client, it
causes a FATAL runtime error. In ALL places I have worked, this as NOT
been acceptable behaviour for a program. It therefore means that
exception specifications CANNOT be used, except in some places where
you have to use throw() in order to get certain compilers to actually
inline inline functions (and you have to then be pretty sure that
anything called doesn't throw).
Or you would end up with an enormous number of catch()-blocks where
humans can prove that the will never be reached, but the compilers
can't.
You have evidence for that, or is that, as I suspect, just FUD. If you
throw only exception X, then you will only need try/catch blocks where
you call something that has a looser exception specification than you
do. This is possible if you are retrofitting this to existing code and
trying to do it top down rather than bottom up. In the vast majority of
other cases, it will be because you have a potential runtime error.
2) A specific exception, e.g. std::runtime_error
But as an author of a templated library (like Boost or Loki), how would
I know which exception is suitable for my users?
Don't use an exception specification then.
Because it is not an exception that is generated by my code, but it is
generated in a function provided by the user and only passes through my
code.
No, it won't pass through your code. If will cause your code to CRASH,
to CEASE, to STOP DEAD, to FALL OVER IN A NASTY HEAP if you use an
exception specification. And that is simply not acceptable in many
situations.
For that reason, translating the exception from the user into something
else is not acceptable, because it means an inevitable loss of
information.
For that reason, you cannot have an exception specification. Because if
you do, under the current situation, your program will CRASH, CEASE,
STOP DEAD, FALL OVER IN A NASTY HEAP because the compiler inserts code
to check at runtime something that it could have checked at compile
time.
3) A template, such as
template <class T> T* createDefault() throw(std::bad_alloc,
my_exception<T>)
{
return new T();
}
And then the client must be forced into the mold that I have created.
But what if the same function is used in two templated libraries, where
both expect different, incompatible, exception specifications?
Then, under the current regime, your program CRASH, CEASE, STOP DEAD,
FALL OVER IN A NASTY HEAP because the compiler inserts code to check at
runtime something that it could have checked at compile time.
Agreed, you'd have to rewrite your code slightly, as
void foo() throw(std::bad_alloc)
{
try {
A* a = createDefault<A>();
}
catch (my_exception<A> &) { }
try
{
B* b = createDefault<B>();
}
catch(my_exception<B>& )
{
}
}
But why would I have to try to catch an exception that can provably
never be thrown?
It's a template, how can you prove it'll never be thrown? You complain
because if its a template you don't know what exceptions might be
thrown, and now you complain because you know a certain exception will
never be thrown. You can't have it both ways.
A template still specificies an interface to be implemented, and you
must then consider how much you care about the exceptions which you
desire your implementation to throw.
This is where we differ in opinion.
If you want to consider the exception specification as part of the
interface contract, then there must be a way to specify 'I might throw
these exceptions, plus whatever the client-provided code throws'.
That's what the example I did above does. Remember that the throw spec
includes all classes derived from the specified class.
The main thing that I am concerned with is that, if I call a
client-provided function and that function decides to throw an
exception, then that exception must pass through my code without
breaking anything.
Then in the current regime, you can't provide an exception
specification, because if you do, your code will will CRASH, CEASE,
STOP DEAD, FALL OVER IN A NASTY HEAP because the compiler inserts code
to check at runtime something that it could have checked at compile
time.
In other words, as long as my code has a sufficient level of exception
correctness, I could not care less what exceptions might pass through.
I'll just have to repeat what I said above. Under the current regime,
you can't provide an exception specification, because if you do, your
code will will CRASH, CEASE, STOP DEAD, FALL OVER IN A NASTY HEAP
because the compiler inserts code to check at runtime something that it
could have checked at compile time. In what way would providing compile
time checks make this worse?
It is NOT ACCEPTABLE for particular classes of software to crash. And
therefore you can't use exception specifications in those classes of
software without compile time checks.
Bart v Ingen Schenau
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]