Destructor call of virtual base class - what happens with exception spec?

Discussion in 'C++' started by Johannes Schaub (litb), Sep 13, 2010.

  1. I tried to force programmers of a derived class to explicitly define a
    constructor (just for fun). This is what i came up with:

    struct Viral {
    struct Dose { };
    protected:
    ~Viral() throw (Dose) { }
    };

    struct Base : virtual Viral {
    virtual ~Base() throw() { }
    };

    struct Derived : Base { };

    It's an illegal program because Derived::~Derived calls ~Viral, so it
    includes (Dose) in its exception spec, but as it overrides ~Base, it will
    have a looser exception spec and is this illegal. The user explicitly needs
    to overrideit

    struct Derived : Base { ~Derived() throw() { } }; // OK

    Clang rejects the code with the implicitly defined destructor, but GCC and
    comeau online accept it, which surprises me.

    Are clang and me right, or are we wrong and the other two are right?
    Johannes Schaub (litb), Sep 13, 2010
    #1
    1. Advertising

  2. Johannes Schaub (litb)

    Gil Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 13, 10:53 am, "Johannes Schaub (litb)" <>
    wrote:
    > I tried to force programmers of a derived class to explicitly define a
    > constructor (just for fun). This is what i came up with:
    >
    > struct Viral {
    > struct Dose { };
    > protected:
    > ~Viral() throw (Dose) { }
    >
    > };
    >
    > struct Base : virtual Viral {
    > virtual ~Base() throw() { }
    >
    > };
    >
    > struct Derived : Base { };
    >
    > It's an illegal program because Derived::~Derived calls ~Viral, so it
    > includes (Dose) in its exception spec, but as it overrides ~Base, it will
    > have a looser exception spec and is this illegal. The user explicitly needs
    > to overrideit
    >
    > struct Derived : Base { ~Derived() throw() { } }; // OK
    >
    > Clang rejects the code with the implicitly defined destructor, but GCC and
    > comeau online accept it, which surprises me.
    >
    > Are clang and me right, or are we wrong and the other two are right?


    MIOS (my interpretation of standard): you are right;
    in your example, implicitly declared Derived::~Derived should come
    with an implicit exception specification that is against 15.4/3 with
    regard to overriding Base::~Base.
    Gil, Sep 13, 2010
    #2
    1. Advertising

  3. Johannes Schaub (litb)

    Kai-Uwe Bux Guest

    Balog Pal wrote:

    >
    > "Johannes Schaub (litb)"
    >>I tried to force programmers of a derived class to explicitly define a
    >> constructor (just for fun). This is what i came up with:
    >>
    >> struct Viral {
    >> struct Dose { };
    >> protected:
    >> ~Viral() throw (Dose) { }
    >> };
    >>
    >> struct Base : virtual Viral {
    >> virtual ~Base() throw() { }
    >> };
    >>
    >> struct Derived : Base { };
    >>
    >> It's an illegal program because Derived::~Derived calls ~Viral, so it
    >> includes (Dose) in its exception spec, but as it overrides ~Base, it will
    >> have a looser exception spec and is this illegal. The user explicitly
    >> needs
    >> to overrideit
    >>
    >> struct Derived : Base { ~Derived() throw() { } }; // OK
    >>
    >> Clang rejects the code with the implicitly defined destructor, but GCC
    >> and comeau online accept it, which surprises me.
    >>
    >> Are clang and me right, or are we wrong and the other two are right?

    >
    > Does it matter when there is so wide consensus that dtors shall not throw?


    Note that none of the constructors above throws. One of them just has a
    throw specification that "reserves the right" to throw. The constructor as
    shown, however, does not.

    I don't know whether there is a consensus about throw-specifications of
    constructors.

    > And almost that wide to not write exceptions specs?


    Sure it matters. Since two compilers disagree on whether the code is well-
    formed, we want to know _where_ to file a bug report :)

    > Who would allow those fragments into any real program? I'd definitely not.


    Well, his trickery about throw specifications (once thoroughly understood)
    is about making the compiler barf at certain inputs and thereby forcing the
    client of some library to code in a certain way. Such techniques, per se,
    might prove useful in some circumstances; and I cannot rule out that the
    "throw-spec-trick" could become part of such a technique.


    Best

    Kai-Uwe Bux
    Kai-Uwe Bux, Sep 13, 2010
    #3
  4. Johannes Schaub (litb)

    Balog Pal Guest

    "Kai-Uwe Bux" <>

    >> Does it matter when there is so wide consensus that dtors shall not
    >> throw?

    >
    > Note that none of the constructors above throws. One of them just has a
    > throw specification that "reserves the right" to throw. The constructor as
    > shown, however, does not.
    >
    > I don't know whether there is a consensus about throw-specifications of
    > constructors.


    I was talking about destructors, not constructors. ctors are the best
    candidates to throw, as other options to signal a problem are limited or
    problematic.

    While exceptions escaping dtors can wreak much havoc so many many template
    libraries, including STL just call it UB if the subject does so.

    Handling the consequences is problematic too -- and the most evil thing is
    that call of other destructors gets prevented, killing the ctor/dtor
    symmetry most good design builds on in a C++ program.

    >> And almost that wide to not write exceptions specs?

    >
    > Sure it matters. Since two compilers disagree on whether the code is well-
    > formed, we want to know _where_ to file a bug report :)


    LOL. Certainly I agree that the standard's verdict is better be clear, and
    implementations do it corectly. :) Just IIRC exception spec is already
    deprecated in c++0x -- and some widely used implementations deliberately
    make it for different semantics.

    >> Who would allow those fragments into any real program? I'd definitely
    >> not.

    >
    > Well, his trickery about throw specifications (once thoroughly understood)
    > is about making the compiler barf at certain inputs and thereby forcing
    > the
    > client of some library to code in a certain way. Such techniques, per se,
    > might prove useful in some circumstances; and I cannot rule out that the
    > "throw-spec-trick" could become part of such a technique.


    Ah, I didn't think about such use. But it seems practice makes its
    usability too limited for real practice.
    Balog Pal, Sep 13, 2010
    #4
  5. Johannes Schaub (litb)

    James Kanze Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    > "Johannes Schaub (litb)"


    [...]
    > Does it matter when there is so wide consensus that dtors
    > shall not throw?


    There is wide consensus that destructors usually should not
    throw. There is even wider consensus that every rule may have
    exceptions, and I have at least one class whose destructor
    always throws.

    > And almost that wide to not write exceptions specs?


    Except for empty ones.

    --
    James Kanze
    James Kanze, Sep 14, 2010
    #5
  6. Re: Destructor call of virtual base class - what happens with exceptionspec?

    James Kanze wrote:
    > On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    >> "Johannes Schaub (litb)"

    >
    > [...]
    >> Does it matter when there is so wide consensus that dtors
    >> shall not throw?

    >
    > There is wide consensus that destructors usually should not
    > throw. There is even wider consensus that every rule may have
    > exceptions, and I have at least one class whose destructor
    > always throws.


    Sounds like a hack. Can you explain why it always throws?
    Vladimir Jovic, Sep 14, 2010
    #6
  7. Vladimir Jovic wrote:

    > James Kanze wrote:
    >> On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    >>> "Johannes Schaub (litb)"

    >>
    >> [...]
    >>> Does it matter when there is so wide consensus that dtors
    >>> shall not throw?

    >>
    >> There is wide consensus that destructors usually should not
    >> throw. There is even wider consensus that every rule may have
    >> exceptions, and I have at least one class whose destructor
    >> always throws.

    >
    > Sounds like a hack. Can you explain why it always throws?


    It may be useful for noreturn functions, i think:

    struct noreturn {
    ~noreturn() {
    if(!uncaught_exception())
    throw logical_error("dude, why do you return?");
    }
    };

    void myexit() {
    noreturn n;
    /* magic syscall sex */

    }
    Johannes Schaub (litb), Sep 14, 2010
    #7
  8. Johannes Schaub (litb)

    red floyd Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 14, 2:59 am, Vladimir Jovic <> wrote:
    > James Kanze wrote:
    > > On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    > >> "Johannes Schaub (litb)"

    >
    > >     [...]
    > >> Does it matter when there is so wide consensus that dtors
    > >> shall not throw?

    >
    > > There is wide consensus that destructors usually should not
    > > throw.  There is even wider consensus that every rule may have
    > > exceptions, and I have at least one class whose destructor
    > > always throws.

    >
    > Sounds like a hack. Can you explain why it always throws?


    I once saw something like the following nonignorable:

    template<typename T>
    class nonignorable {
    public:
    nonignorable(const T& t) : was_read(false), val(t) { }
    operator T() const { was_read = true; return val; }
    ~nonignorable() {
    if (!was_read)
    throw logic_error("you ignored me!");
    }
    private:
    bool was_read;
    T val;
    };

    The idea was to ensure that a function return value was used,
    or explicitly ignored, e.g.:

    nonignorable<int> somefunc()
    {
    // do stuff
    return some_integer;
    }
    red floyd, Sep 14, 2010
    #8
  9. Johannes Schaub (litb)

    red floyd Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 14, 1:06 pm, red floyd <> wrote:

    Oops: missed a copy constructor and assignment op in there:

    > template<typename T>
    > class nonignorable {
    >     public:
    >         nonignorable(const T& t) : was_read(false), val(t) { }

    nonignorable(nonignorable<T>& t) : was_read(false),
    val(t.val)
    {
    t.was_read = true;
    }
    nonignorable& operator=(nonignorable<T>& t)
    {
    t.was_read = true;
    val = t.val;
    return *this;
    }

    // this should probably be an explicit "get()" op
    >         operator T() const { was_read = true; return val; }
    >         ~nonignorable() {
    >             if (!was_read)
    >                 throw logic_error("you ignored me!");
    >          }
    >     private:
    >          bool was_read;
    >          T val;
    >
    > };
    >
    red floyd, Sep 14, 2010
    #9
  10. Johannes Schaub (litb)

    James Kanze Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 14, 10:59 am, Vladimir Jovic <> wrote:
    > James Kanze wrote:
    > > On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    > >> "Johannes Schaub (litb)"


    > > [...]
    > >> Does it matter when there is so wide consensus that dtors
    > >> shall not throw?


    > > There is wide consensus that destructors usually should not
    > > throw. There is even wider consensus that every rule may have
    > > exceptions, and I have at least one class whose destructor
    > > always throws.


    > Sounds like a hack. Can you explain why it always throws?


    Because that's its defined semantics.

    The class in question is used to support complex error messages
    in exceptions. So you write something like:
    error() << "xyz = " << xyz;
    The function error returns an instance of the class, which
    collects the output in a ostringstream, and throws the exception
    with the generated output in its destructor. (It's actually
    a bit more complicated, since you need support copy for the
    return value of error(), and you only throw when the last copy
    is destructed. You also have to check for other exceptions in
    the destructor, and just let them propagate, without throwing
    yours.)

    --
    James Kanze
    James Kanze, Sep 15, 2010
    #10
  11. Johannes Schaub (litb)

    James Kanze Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 14, 9:06 pm, red floyd <> wrote:
    > On Sep 14, 2:59 am, Vladimir Jovic <> wrote:


    > > James Kanze wrote:
    > > > On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    > > >> "Johannes Schaub (litb)"


    > > > [...]
    > > >> Does it matter when there is so wide consensus that dtors
    > > >> shall not throw?


    > > > There is wide consensus that destructors usually should not
    > > > throw. There is even wider consensus that every rule may have
    > > > exceptions, and I have at least one class whose destructor
    > > > always throws.


    > > Sounds like a hack. Can you explain why it always throws?


    > I once saw something like the following nonignorable:


    > template<typename T>
    > class nonignorable {
    > public:
    > nonignorable(const T& t) : was_read(false), val(t) { }
    > operator T() const { was_read = true; return val; }
    > ~nonignorable() {
    > if (!was_read)
    > throw logic_error("you ignored me!");
    > }
    > private:
    > bool was_read;
    > T val;
    > };


    > The idea was to ensure that a function return value was used,
    > or explicitly ignored, e.g.:


    > nonignorable<int> somefunc()
    > {
    > // do stuff
    > return some_integer;
    > }


    That's usually an assertion in the destructor, and not a thrown
    exception. And you might want to check if the destructor is
    being called before asserting---an intervening exception might
    mean that it's OK not to check the return value.

    --
    James Kanze
    James Kanze, Sep 15, 2010
    #11
  12. Re: Destructor call of virtual base class - what happens with exceptionspec?

    James Kanze wrote:
    > On Sep 14, 10:59 am, Vladimir Jovic <> wrote:
    >> James Kanze wrote:
    >>> On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    >>>> "Johannes Schaub (litb)"

    >
    >>> [...]
    >>>> Does it matter when there is so wide consensus that dtors
    >>>> shall not throw?

    >
    >>> There is wide consensus that destructors usually should not
    >>> throw. There is even wider consensus that every rule may have
    >>> exceptions, and I have at least one class whose destructor
    >>> always throws.

    >
    >> Sounds like a hack. Can you explain why it always throws?

    >
    > Because that's its defined semantics.
    >
    > The class in question is used to support complex error messages
    > in exceptions. So you write something like:
    > error() << "xyz = " << xyz;
    > The function error returns an instance of the class, which
    > collects the output in a ostringstream, and throws the exception
    > with the generated output in its destructor. (It's actually
    > a bit more complicated, since you need support copy for the
    > return value of error(), and you only throw when the last copy
    > is destructed. You also have to check for other exceptions in
    > the destructor, and just let them propagate, without throwing
    > yours.)
    >
    > --
    > James Kanze


    Is there a good reason (other than terseness) for preferring that to e.g.

    throw exception(stringbuilder() << "xyz = " << xyz);

    ?

    Just curious in case there's a trick I'm missing here (wouldn't be
    surprised).

    Cheers,
    Stu
    Stuart Golodetz, Sep 16, 2010
    #12
  13. Johannes Schaub (litb)

    James Kanze Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 16, 1:13 am, Stuart Golodetz <> wrote:
    > James Kanze wrote:
    > > On Sep 14, 10:59 am, Vladimir Jovic <> wrote:
    > >> James Kanze wrote:
    > >>> On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    > >>>> "Johannes Schaub (litb)"


    > >>> [...]
    > >>>> Does it matter when there is so wide consensus that dtors
    > >>>> shall not throw?


    > >>> There is wide consensus that destructors usually should not
    > >>> throw. There is even wider consensus that every rule may have
    > >>> exceptions, and I have at least one class whose destructor
    > >>> always throws.


    > >> Sounds like a hack. Can you explain why it always throws?


    > > Because that's its defined semantics.


    > > The class in question is used to support complex error messages
    > > in exceptions. So you write something like:
    > > error() << "xyz = " << xyz;
    > > The function error returns an instance of the class, which
    > > collects the output in a ostringstream, and throws the exception
    > > with the generated output in its destructor. (It's actually
    > > a bit more complicated, since you need support copy for the
    > > return value of error(), and you only throw when the last copy
    > > is destructed. You also have to check for other exceptions in
    > > the destructor, and just let them propagate, without throwing
    > > yours.)


    > Is there a good reason (other than terseness) for preferring that to e.g.


    > throw exception(stringbuilder() << "xyz = " << xyz);


    > ?


    Coherence with other error handling mechanisms. But you're
    right that it's a bit obfuscating: someone reading the code
    doesn't realize that code after this line is unreachable,
    however, since the "throw" isn't visible. It's probably not
    that good of an idea, although I've seen it used.

    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.)

    --
    James Kanze
    James Kanze, Sep 16, 2010
    #13
  14. Re: Destructor call of virtual base class - what happens with exceptionspec?

    James Kanze wrote:
    > On Sep 16, 1:13 am, Stuart Golodetz <> wrote:
    >> James Kanze wrote:
    >>> On Sep 14, 10:59 am, Vladimir Jovic <> wrote:
    >>>> James Kanze wrote:
    >>>>> On Sep 13, 9:52 pm, "Balog Pal" <> wrote:
    >>>>>> "Johannes Schaub (litb)"

    >
    >>>>> [...]
    >>>>>> Does it matter when there is so wide consensus that dtors
    >>>>>> shall not throw?

    >
    >>>>> There is wide consensus that destructors usually should not
    >>>>> throw. There is even wider consensus that every rule may have
    >>>>> exceptions, and I have at least one class whose destructor
    >>>>> always throws.

    >
    >>>> Sounds like a hack. Can you explain why it always throws?

    >
    >>> Because that's its defined semantics.

    >
    >>> The class in question is used to support complex error messages
    >>> in exceptions. So you write something like:
    >>> error() << "xyz = " << xyz;
    >>> The function error returns an instance of the class, which
    >>> collects the output in a ostringstream, and throws the exception
    >>> with the generated output in its destructor. (It's actually
    >>> a bit more complicated, since you need support copy for the
    >>> return value of error(), and you only throw when the last copy
    >>> is destructed. You also have to check for other exceptions in
    >>> the destructor, and just let them propagate, without throwing
    >>> yours.)

    >
    >> Is there a good reason (other than terseness) for preferring that to e.g.

    >
    >> throw exception(stringbuilder() << "xyz = " << xyz);

    >
    >> ?

    >
    > Coherence with other error handling mechanisms. But you're
    > right that it's a bit obfuscating: someone reading the code
    > doesn't realize that code after this line is unreachable,
    > however, since the "throw" isn't visible. It's probably not
    > that good of an idea, although I've seen it used.


    I guess it is mildly obfuscating, yes :) I wasn't actually trying to
    make a point, though, I was just curious in case there was some reason
    to prefer it over what I do at the moment.

    > 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)?

    (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;
    };

    struct FatalError : Error
    {
    void throw_me(const std::string& msg)
    {
    // etc.
    }
    };

    class ProgramStatus
    {
    //...

    shared_ptr<Error> err_;
    shared_ptr<FatalError> fatal_; // initialized elsewhere

    Error& err()
    {
    assert(err_.get());
    return *err_;
    }

    ThrowingStream setError(const shared_ptr<Error>& err)
    {
    err_ = err;
    return ThrowingStream();
    }
    };

    class ThrowingStream
    {
    //...

    std::eek:stringstream os_;

    template <typename T>
    ThrowingStream& operator<<(const T& t)
    {
    os_ << t;
    return *this;
    }

    ~ThrowingStream()
    {
    if(!uncaught_exception())
    ProgramStatus::instance().err().throw_me(os_.str());
    }
    };

    Cheers,
    Stu

    > --
    > James Kanze
    Stuart Golodetz, Sep 16, 2010
    #14
  15. Johannes Schaub (litb)

    James Kanze Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 16, 7:12 pm, Stuart Golodetz <> wrote:
    > James Kanze wrote:
    > > On Sep 16, 1:13 am, Stuart Golodetz <> wrote:
    > >> James Kanze wrote:
    > >>> On Sep 14, 10:59 am, Vladimir Jovic <> wrote:
    > >>>> James Kanze wrote:
    > >>>>> On Sep 13, 9:52 pm, "Balog Pal" <> 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::eek:stringstream 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
    James Kanze, Sep 17, 2010
    #15
  16. Re: Destructor call of virtual base class - what happens with exceptionspec?

    James Kanze wrote:
    > On Sep 16, 7:12 pm, Stuart Golodetz <> wrote:
    >> James Kanze wrote:
    >>> On Sep 16, 1:13 am, Stuart Golodetz <> wrote:
    >>>> James Kanze wrote:
    >>>>> On Sep 14, 10:59 am, Vladimir Jovic <> wrote:
    >>>>>> James Kanze wrote:
    >>>>>>> On Sep 13, 9:52 pm, "Balog Pal" <> 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?


    Possibly -- it's not a very well-thought-through design to be honest, I
    was just trying to hack out the idea.

    >> };
    >>
    >> 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.


    fatal_ should indeed be static -- I wasn't thinking straight :) And
    err_ could be static too I suppose.

    No reason for using shared_ptr; I guess it's bad that that was the first
    solution that sprang to mind(?)

    I guess I could (should?) have just used e.g.

    Error *err_;
    static FatalError fatal_;
    // etc.

    Oh well :) That'll teach me to post half-baked pseudo-code I guess...

    Cheers,
    Stu

    >> Error& err()
    >> {
    >> assert(err_.get());
    >> return *err_;
    >> }

    >
    >> ThrowingStream setError(const shared_ptr<Error>& err)
    >> {
    >> err_ = err;
    >> return ThrowingStream();
    >> }
    >> };

    >
    >> class ThrowingStream
    >> {
    >> //...

    >
    >> std::eek:stringstream 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
    Stuart Golodetz, Sep 17, 2010
    #16
  17. Johannes Schaub (litb)

    James Kanze Guest

    Re: Destructor call of virtual base class - what happens withexception spec?

    On Sep 17, 2:21 pm, Stuart Golodetz <> wrote:
    > James Kanze wrote:


    [...]
    > Oh well :) That'll teach me to post half-baked pseudo-code I guess...


    No. Almost all good ideas start out as half-baked pseudo-code.
    It's through discussion that they become solid code.

    --
    James Kanze
    James Kanze, Sep 18, 2010
    #17
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chunhui Han
    Replies:
    2
    Views:
    500
  2. qazmlp
    Replies:
    1
    Views:
    565
    qazmlp
    Apr 10, 2005
  3. frs
    Replies:
    20
    Views:
    752
    Alf P. Steinbach
    Sep 21, 2005
  4. LAvoisieR
    Replies:
    8
    Views:
    430
    LAvoisieR
    Oct 27, 2005
  5. sojin
    Replies:
    12
    Views:
    1,882
Loading...

Share This Page