NoThrow.h
// NoThrow.h
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2021
#pragma once
#ifndef Ceda_cxUtils_NoThrow_H
#define Ceda_cxUtils_NoThrow_H
#include <exception>
/*
std::uncaught_exceptions() returns the number of active exceptions. To check whether the stack is unwinding
from an exception, a Transaction class can be written like this:
class Transaction
{
public:
Transaction(){}
Transaction(const Transaction&) = delete;
Transaction& operator =(const Transaction&) = delete;
void Commit();
~Transaction()
{
if (uncaughtExceptionCount == std::uncaught_exceptions())
{
Commit(); // May throw.
}
else
{
// Stack is unwinding, we assume it is too risky to allow
// the transaction to commit, and instead terminate the process
std::terminate();
}
}
private:
int uncaughtExceptionCount = std::uncaught_exceptions();
};
If there isn't a try / catch block in the stack that catches the exception that was thrown,
then the stack never unwinds (so ~Transaction() is never called). Instead the program
terminates because of an unhandled exception. This is probably a good result because it means
the debugger breaks at the line of code which caused the unhandled exception.
It's a bad idea to catch exceptions you don't handle. Even catching with ... and rethrowing stops
the visual studio debugger stopping at the point where an access violation occurred etc, so
debugging is much harder than it needs to be. This is very important for efficient software
development.
Under Windows, CEDA is compiled with /EHsc. This results in more efficient code than with /EHa.
It is more space and time efficient for x86 code, and more space efficient for x64 code.
/EHsc means asynchronous exceptions such as integer division by zero or access violations are
not caught with try-catch(...) and stack unwinding doesn't deal correctly with these kinds of
exceptions.
Access violations and integer divide by zero are regarded as serious programming errors and the
best thing to do is immediately abort the program, regardless of which thread was involved. That is the
normal behaviour. If you're in the debugger then the debugger should stop with the offending
thread at the offending code. If you're not in the debugger it is possible that the program
silently aborts (i.e. without a message box).
*/
namespace ceda
{
class CheckStackUnwinding
{
public:
bool StackIsUnwinding() const
{
return uncaughtExceptionCount_ != std::uncaught_exceptions();
}
private:
int uncaughtExceptionCount_ = std::uncaught_exceptions();
};
} // namespace ceda
#endif // include guard