I'm trying to create a class with a "mostly-invariant" that allows clients to break the invariant if need be but only if they fix it before leaving the scope in which the nastiness happens.
Here are the two classes involved. It's similar to scope guard. More details, comments, and a small test at ideone.
class HCAccessor;
class HasConditions
{
// class "mostly-invariant"
// 7 < payload_ <42
int payload_;
bool valid() const
{
if (!(7 < payload_) || !(payload_ < 42))
return false;
else
return true;
}
public:
HasConditions(const int payload)
: payload_(payload)
{
if (!valid())
{
throw std::runtime_error("can't construct");
}
}
friend class HCAccessor;
};
class HCAccessor
{
HasConditions& hc_;
public:
HCAccessor(HasConditions& hc)
: hc_(hc)
{}
HCAccessor(HCAccessor& other)
: hc_(other.hc_)
{}
~HCAccessor()
{
if (!hc_.valid())
{
throw std::runtime_error("you broke it!");
}
}
void payload(const int newval)
{
hc_.payload_ = newval;
}
int payload() const
{
return hc_.payload_;
}
};
When the "mostly-invariant" is broken and then fixed the code seems to work. When the "mostly-invariant" remains broken and ~HCAccessor()
throws, std::terminate
gets called and I don't know why. None of the reasons for an exception resulting in a std::terminate
call seem to fit.
http://en.cppreference.com/w/cpp/error/terminate
As far as I can tell only one exception is thrown and then immediately std::terminate
is called.
Why is this happening and how can I fix it?