[contract] invariant checking after destructor throw

I have found a potential issue while reading the documentation. (The documentation is very good BTW). It says that the non-static invariant is still checked if object's destructor throws an exception. Am I reading it right? If so, I believe this is not correct. I have two problems with it: 1. According to the standard, an object is considered destroyed (its life-time has ended) when its destructor *starts*. Even if it throws an exception, it is considered destroyed, so accessing its members (in order to check for the invariant) may be illegal (an undefined behavior). 2. Why such an object (that threw on destruction) would need to preserve the invariant? You cannot access it or use it or even destroy it the second time, because it has already been destroyed. No-one will notice it anyway. Or am I missing something? Regards, &rzej

On Tue, Aug 28, 2012 at 1:02 PM, Andrzej Krzemienski <akrzemi1@gmail.com> wrote:
I have found a potential issue while reading the documentation. (The documentation is very good BTW). It says that the non-static invariant is still checked if object's destructor throws an exception. Am I reading it right? If so, I believe this is not correct. I have two problems with it:
1. According to the standard, an object is considered destroyed (its life-time has ended) when its destructor *starts*. Even if it throws an exception, it is considered destroyed, so accessing its members (in order to check for the invariant) may be illegal (an undefined behavior). 2. Why such an object (that threw on destruction) would need to preserve the invariant? You cannot access it or use it or even destroy it the second time, because it has already been destroyed. No-one will notice it anyway.
Or am I missing something?
I think you are right... I swear I read somewhere that destructor abnormal exit (on throw) should still check class invariants but I just double checked N1962 and N1613, that doesn't seem to be the case. On the contrary, N1962 says: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html#class-inv... `` 3. It (the class invariant) is called implicitly from public a. pre- and postconditions, b. constructors, call the class invariant before the postcondition, c. destructors, call the class invariant before the destructor body. d. member functions that exit abnormally via an exception [5] [5] To ensure that the function gives the basic guarantee of exception-safety. '' Which is consistent with your argument... Also, if the standard says no object after destructor starts then invariants apply no more. In any case, this is trivial to fix. I entered a ticket for it: https://sourceforge.net/apps/trac/contractpp/ticket/66 I'll double check a few sources (N-papers, standard, and Eiffel) and if this is indeed a bug, consider it fixed. Thanks for catching this! --Lorenzo

on Tue Aug 28 2012, Andrzej Krzemienski <akrzemi1-AT-gmail.com> wrote:
I have found a potential issue while reading the documentation. (The documentation is very good BTW). It says that the non-static invariant is still checked if object's destructor throws an exception. Am I reading it right? If so, I believe this is not correct. I have two problems with it:
1. According to the standard, an object is considered destroyed (its life-time has ended) when its destructor *starts*. Even if it throws an exception, it is considered destroyed, so accessing its members (in order to check for the invariant) may be illegal (an undefined behavior).
It's not undefined behavior. The members and bases are not yet destroyed. Otherwise, how would you release any resources held in mmebers?
2. Why such an object (that threw on destruction) would need to preserve the invariant? You cannot access it or use it or even destroy it the second time, because it has already been destroyed. No-one will notice it anyway.
This is still a good question. -- Dave Abrahams BoostPro Computing Software Development Training http://www.boostpro.com Clang/LLVM/EDG Compilers C++ Boost

2012/9/3 Dave Abrahams <dave@boostpro.com>
on Tue Aug 28 2012, Andrzej Krzemienski <akrzemi1-AT-gmail.com> wrote:
1. According to the standard, an object is considered destroyed (its life-time has ended) when its destructor *starts*. Even if it throws an exception, it is considered destroyed, so accessing its members (in order to check for the invariant) may be illegal (an undefined behavior).
It's not undefined behavior. The members and bases are not yet destroyed. Otherwise, how would you release any resources held in mmebers?
Perhaps I am being imprecise. What I mean is that at the time the invariant would be executed, the exception would have "left" the destructor of the derived class, so members and bases would have been destroyed. Regards, &rzej

On Mon, Sep 3, 2012 at 1:47 PM, Dave Abrahams <dave@boostpro.com> wrote:
on Tue Aug 28 2012, Andrzej Krzemienski <akrzemi1-AT-gmail.com> wrote:
I have found a potential issue while reading the documentation. (The documentation is very good BTW). It says that the non-static invariant is still checked if object's destructor throws an exception. Am I reading it right? If so, I believe this is not correct. I have two problems with it:
1. According to the standard, an object is considered destroyed (its life-time has ended) when its destructor *starts*. Even if it throws an exception, it is considered destroyed, so accessing its members (in order to check for the invariant) may be illegal (an undefined behavior).
It's not undefined behavior. The members and bases are not yet destroyed. Otherwise, how would you release any resources held in mmebers?
2. Why such an object (that threw on destruction) would need to preserve the invariant? You cannot access it or use it or even destroy it the second time, because it has already been destroyed. No-one will notice it anyway.
This is still a good question.
Yes, it's a good question and it would seem that N1962 specifies only member functions (not destructors) abnormal exit: `` 3. It (the class invariant) is called implicitly from public a. pre- and postconditions, b. constructors, call the class invariant before the postcondition, c. destructors, call the class invariant before the destructor body. d. member functions that exit abnormally via an exception [5] [5] To ensure that the function gives the basic guarantee of exception-safety. '' I think checking invariants on destructor abnormal exit is a defect of the current implementation (btw, trivial to fix) but I reserve to double check with all the references that I looked at when implementing the lib before fixing it. Thanks, --Lorenzo
participants (3)
-
Andrzej Krzemienski
-
Dave Abrahams
-
Lorenzo Caminiti