// Sample: sink all exceptions in one place and translate to return code
// Author: Mateusz Loskot <mateusz at loskot dot net>
#include <cassert>
#include <exception>
#include <iostream>
#include <stdexcept>
template <typename T>
inline T const& handle_exception(char const* const who, T const& rc)
{
try
{
throw;
}
catch (int e)
{
std::cerr << who << " caught int: " << e << std::endl;
}
catch (char const* e)
{
std::cerr << who << " caught c-string: " << e << std::endl;
}
catch (std::exception const& e)
{
std::cerr << who << " caught std::exception: " << e.what() << std::endl;
}
return rc;
}
#define EXCEPTION_TRY() \
try {
#define EXCEPTION_CATCH_AND_RETURN(success, failure) \
} catch (...) { \
return handle_exception(__FUNCTION__, failure); \
} \
return success;
#define EXCEPTION_CATCH_AND_EXIT() \
} catch (...) { handle_exception(__FUNCTION__, false); return; }
template <typename T>
class number
{
public:
// public ctor, may throw
number(T value) : value_(value)
{
if (value != value)
throw "value is NaN";
}
// public save division, never throws,
bool divide_s(double& result, T const& den) const
{
EXCEPTION_TRY()
result = divide_(value_, den);
EXCEPTION_CATCH_AND_RETURN(true, false)
}
private:
T value_;
// used internally by other private methods, allowed to throw
double divide_(T const& num, T const& den) const
{
if (den > 0)
{
return num / den;
}
throw std::invalid_argument("denominator is zero");
}
};
// C wrapper is not allowed to throw exceptions
double divide_numbers(double num, double den)
{
EXCEPTION_TRY()
number<double> n(num);
double r = 0;
n.divide_s(r, den);
EXCEPTION_CATCH_AND_RETURN(true, false)
}
int main()
{
bool success(false);
double result(0);
// Using C++ interface
{
number<int> n(10);
// no error logged
success = n.divide_s(result, 2);
assert(success);
// error logged, flag returned
success = n.divide_s(result, 0);
assert(!success);
}
// Using C interface
{
// no error logged
result = divide_numbers(10, 2);
// error logged
result = divide_numbers(10, 0);
// error logged
float nan = 0;
result = divide_numbers(nan / 0, 10);
}
}