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