Re: Defining undefined, etc., behavior
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.
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.
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?
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.
For that reason, translating the exception from the user into something
else is not acceptable, because it means an inevitable loss of
information.
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?
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?
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'.
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.
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.
Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
---
[ 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 ]