Re: Destructor call of virtual base class - what happens with
exception spec?
On Sep 16, 7:12 pm, Stuart Golodetz <b...@blah.com> wrote:
James Kanze wrote:
On Sep 16, 1:13 am, Stuart Golodetz <b...@blah.com> wrote:
James Kanze wrote:
On Sep 14, 10:59 am, Vladimir Jovic <vladasp...@gmail.com> wrote:
James Kanze wrote:
On Sep 13, 9:52 pm, "Balog Pal" <p...@lib.hu> wrote:
"Johannes Schaub (litb)"
[...]
In my case, it's a bit more complicated. I have a singleton
class, ProgramStatus, which handles error output and the return
code (which should correspond to the worst error seen). For
fatal errors, I allow the programmer to define what happens: the
default is just to call exit, but in most cases, I'll replace
that with a function which throws an int. So if you call:
ProgramStatus::instance().setError( ProgramStatus::fatal )
<< ...
, the destructor will (very indirectly) throw. (When I set this
error handling, obviously, main consists of one big try block,
with a:
catch ( int returnCode ) {
return returnCode;
}
at the end. This has the advantage, compared to exit, that
destructors of local variables are called.)
Sounds quite cunning :-) So are you essentially doing something like
this (ignoring any minor syntax problems -- I'm just typing this out
rather than actually trying it)?
It's much, much simpler: no fancy classes are involved, just an
additional variable in the error message collector. Basically,
when I call ProgramStatus::setError(gravity), I return a message
collector which memorizes the gravity, and in its final
destructor, acts on it: if the gravity is "fatal", it calls
ProgramStatus::terminate( returnCode ), which in turn calls
whatever function the client has registered (exit( returnCode
) by default). In most of my programs, I register a function
which just does "throw returnCode". (Throwing an *int*. It's
the only case I've found where it seems appropriate to throw
anything but something derived from std::exception.)
(I'm aware that I've probably messed something up in there, just
wondering whether that's the general gist? :-))
struct Error
{
virtual ~Error() {}
virtual void throw_me(const std::string& msg) = 0;
You mean to provide an implementation which does nothing here,
no? Rather than making it pure virtual?
};
struct FatalError : Error
{
void throw_me(const std::string& msg)
{
// etc.
}
};
class ProgramStatus
{
//...
shared_ptr<Error> err_;
shared_ptr<FatalError> fatal_; // initialized elsewhere
Just curious, but why the shared_ptr? What's wrong with just
making them static.
Error& err()
{
assert(err_.get());
return *err_;
}
ThrowingStream setError(const shared_ptr<Error>& err)
{
err_ = err;
return ThrowingStream();
}
};
class ThrowingStream
{
//...
std::ostringstream os_;
template <typename T>
ThrowingStream& operator<<(const T& t)
{
os_ << t;
return *this;
}
~ThrowingStream()
{
if(!uncaught_exception())
ProgramStatus::instance().err().throw_me(os_.str());
This is probably the hard part. About the only exception you
might get here is std::bad_alloc. Which you probably want to
replace whatever exception you're generating, because it is more
critical.
}
};
--
James Kanze