From: Mathias Gaunard on
On Jun 29, 9:35 pm, Jens Auer <jens.muad...(a)googlemail.com> wrote:

> I don't know how to automatically implement the invariant check
> without throwing in the destructor of the InvariantChecker class.

If an invariant is broken, you shouldn't throw, you should abort and
give a stack dump.
Breaking an invariant is not recoverable.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: ThosRTanner on
On Jun 30, 3:25 pm, Nick Hounsome <nick.houns...(a)gmail.com> wrote:
> On 29 June, 21:35, Jens Auer <jens.muad...(a)googlemail.com> wrote:
>
>
>
>
>
> > I am trying to implement some tools to ease design by contract. To
> > check invariants automatically at the beginning and end of member
> > functions, I intend to use a helper object which does this in RAII-
> > fashion:
>
> > class InvariantViolation: public std::logic_error
> > {
>
> > };
>
> > class InvariantChecker
> > {
> > public:
> > InvariantChecker( boost::function< bool () > const& predicate):
> > mPredicate( predicate )
> > {
> > _check();
> > }
>
> > ~InvariantChecker()
> > {
> > _check(); // may throw! What else to do?
> > }
>
> > private:
> > void _check() const
> > {
> > if ( !mPredicate() )
> > {
> > throw InvarianViolation();
> > }
> > }
>
> > boost::function< bool () > mPredicate;
>
> > };
>
> > // usage example
> > class IntStack
> > {
> > public:
> > int pop()
> > {
> > InvariantChecker( boost::bind( std::greater_equal(), 0, mSize );
> > // check preconditions and do work. Then check postconditions.
> > }
> > private:
> > int mSize;
>
> > };
>
> > I don't know how to automatically implement the invariant check
> > without throwing in the destructor of the InvariantChecker class. I
> > know that is said everywhere to not throw exceptions in the
> > destructor, but what other options are there to execute the check
> > automatically at the start and end of a function?
>
> It's not a problem provided that you don't check invariants in the
> destructors of checked classes.
>
> The reason for not throwing in destructors is because of the effects
> of throwing whilst unwinding a stack due to a previous thrown
> exception - There is no logical way to handle this so the runtime has
> to call std::terminate.
>
> There should be no need to check in the destructor anyway. In fact it
> is would be logically wrong - If the invariant is checked on exit from
> every other method then it must be valid on entry to the dtor (barring
> random memory corruption) and also invariants are not usualy valid on
> exit from a dtor anyway because the object is destroyed.

Nonetheless the destructor can be called though I doubt at this point
that it matters if the invariants hold or not as on exit from the
destructor, the object doesn't exist.

However, presumably the invariant checker needs to be called during
processing an exception, and this is his problem. Consider

void Thing::somefunc()
{
InvariantChecker();
//do something that makes the invariant invalid
//do something that unexpectedly throws
//finish the processing which restores the invariants to a good
state
}

Now, if the code is properly written, the exception thrown should be
caught and the operation undone or recovered. If however, it isn't,
the InvariantChecker destructor will throw. Which will cause the
program to terminate.

I'm not sure what the process should be here. Arguably he should
suborn the exception, because something has been done that breaks the
class invariants. But I'm not sure how that can be achieved. If he
doesn't suborn the exception, it looks like the operation has
performed correctly, and whatever he does next will blow up.

I don't suppose it's entirely critical as the invariant checker is
called on the entry to each function, though I would have felt that
that was somewhat unnecessary as unless you've been corrupting memory,
on entrance to a method, the invriants must hold true if they held
true on exit from the previous method.

Sooo - I guess you have to resort to checking on entrance and
checking if you're currently processing an exception in the destructor
and logging / ignoring the issue


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: restor on
On 30 June, 16:25, Nick Hounsome <nick.houns...(a)gmail.com> wrote:
> On 29 June, 21:35, Jens Auer <jens.muad...(a)googlemail.com> wrote:
>
> > I don't know how to automatically implement the invariant check
> > without throwing in the destructor of the InvariantChecker class. I
> > know that is said everywhere to not throw exceptions in the
> > destructor, but what other options are there to execute the check
> > automatically at the start and end of a function?
>
> It's not a problem provided that you don't check invariants in the
> destructors of checked classes.
>
> The reason for not throwing in destructors is because of the effects
> of throwing whilst unwinding a stack due to a previous thrown
> exception - There is no logical way to handle this so the runtime has
> to call std::terminate.
>
> There should be no need to check in the destructor anyway. In fact it
> is would be logically wrong - If the invariant is checked on exit from
> every other method then it must be valid on entry to the dtor (barring
> random memory corruption) and also invariants are not usualy valid on
> exit from a dtor anyway because the object is destroyed.

Hi,
I do not think that it is correct. Function is obliged to keep the
invariant when it starts and when it finishes.
It is not obliged (and usually this is impossible) to keep the
invariant in the middle, as it calls other functions. Also private
methods do not need to preserve invariants at all. Also, the
destructors are normal functions and they may re-establish the
invariants. You need to check the state of the object after all the
destructors have been run - and the only way to do it is to use
another destructor.

Regards,
&rzej

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Bart van Ingen Schenau on
On Jun 30, 4:25 pm, Nick Hounsome <nick.houns...(a)gmail.com> wrote:
> On 29 June, 21:35, Jens Auer <jens.muad...(a)googlemail.com> wrote:
>
> > I am trying to implement some tools to ease design by contract. To
> > check invariants automatically at the beginning and end of member
> > functions, I intend to use a helper object which does this in RAII-
> > fashion:
<snip>
> > I don't know how to automatically implement the invariant check
> > without throwing in the destructor of the InvariantChecker class. I
> > know that is said everywhere to not throw exceptions in the
> > destructor, but what other options are there to execute the check
> > automatically at the start and end of a function?
>
> It's not a problem provided that you don't check invariants in the
> destructors of checked classes.

I am sorry, but that is just plain nonsense.
If a failed invariant is reported by throwing an exception, then every
invariant check that occurs during stack unwinding is a potential
cause for abrupt program termination.

As far as I see, the interesting questions here are:
a) Is it reasonable to expect that class-invariants are intact if a
call to a member-function is ended with an exception? And should that
expectation be checked?
b) If you do check for class invariants during stack unwinding, how
can you report a failure?

Bart v Ingen Schenau


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: restor on
On 29 June, 22:35, Jens Auer <jens.muad...(a)googlemail.com> wrote:
> I am trying to implement some tools to ease design by contract. To
> check invariants automatically at the beginning and end of member
> functions, I intend to use a helper object which does this in RAII-
> fashion:
>
> class InvariantViolation: public std::logic_error
> {
>
> };
>
> class InvariantChecker
> {
> public:
> InvariantChecker( boost::function< bool () > const& predicate):
> mPredicate( predicate )
> {
> _check();
> }
>
> ~InvariantChecker()
> {
> _check(); // may throw! What else to do?
> }
>
> private:
> void _check() const
> {
> if ( !mPredicate() )
> {
> throw InvarianViolation();
> }
> }
>
> boost::function< bool () > mPredicate;
>
> };

> I don't know how to automatically implement the invariant check
> without throwing in the destructor of the InvariantChecker class. I
> know that is said everywhere to not throw exceptions in the
> destructor, but what other options are there to execute the check
> automatically at the start and end of a function?

Hi,
Your decision to throw exception on invariant check failure is
controversial in itself. The same arguments that works for assertions
works also for invariant checks: if an invariant is not met it may be
better to stop the application altogether, rather than throw an
exception, catch it and proceed: why would you proceed if your classes
do not meet the invariants?

(I know there have been many discussions on whether assertions should
terminate the program or not. I do not want to say they should abort.
I just want to say that the question is controversial.)

Now, other people in this list suggested checking stack unwinding with
std::uncaught_exception before throwing. I don't find it a good idea
for invariant checking. The invariant should hold even when the
function exits by throwing and exception, and you should check that
too. It is not a question of throwing from destructor really - you
could be checking invariants outside the function without using any
destructors. The real problem is that if exception is thrown from
function, the invariant may not hold, and you should signal it too;
since you decided to signal it by throwing an exception, you need to
throw this second exception. You will be signaling two errors at the
same time: the original error in the function, and the fact that on
this error the function failed to re-establish the invariant.
Double exception cannot be handled by C++, and this is additional
reason for not using exceptions for signaling invariant violations.

Regards,
&rzej

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]