I found a new way to do it. It is non-standard and this is an entirely new way to do it.
So consider using this approach cautiously.
Use the following header file:
SetError.h:
#include <string> // for string class
#ifndef SET_ERROR_IS_DEFINED
#define SET_ERROR_IS_DEFINED
class Error {
public:
int code = 0;
std::string errorMessage;
std::string fileName;
std::string functionName;
Error() {}
Error(int _errorCode, std::string _functionName = "", std::string _errorMessage = "", std::string _fileName = "")
{
code = _errorCode;
functionName = _functionName;
errorMessage = _errorMessage;
fileName = _fileName;
}
};
#if defined(_DEBUG) || !defined(NDEBUG)
#define ___try { _ERROR.code = 0; bool __valid_try_mode_declared;
#define ___success }
#define SetError(pErrorData) __valid_try_mode_declared = true; _ERROR = *pErrorData; delete pErrorData;
#else
#define ___try { _ERROR.code = 0;
#define ___success }
#define SetError(pErrorData) _ERROR = *pErrorData; delete pErrorData;
#endif
#endif
inline Error _ERROR;
Include it everyware.
Example of how to use:
Main.cpp:
#include "SetError.h"
#include <iostream>
bool SomeFunction(int value) ___try;
{
if (value < 0) {
SetError(new Error(10, "SomeFunction", "Some error", "File main.cpp"));
return false;
}
return true;
} ___success; // You mast to warp the function with both ___try and ___success
// These keywords must be at the start and the end of the function!
int main()
{
using namespace std;
bool output = SomeFunction(-1);
if (_ERROR.code != 0) { // This is how you check the error code. using the global _ERROR object
cout << "error code: " << _ERROR.code << ", from function: "
<< _ERROR.functionName << ", from file: " << _ERROR.fileName;
}
cout << endl << "Founction returned: " << output << endl;
return 1;
}
If you have some functions that run in another thread, these functions need to be inside namespace and then you can do this:
namespace FunctionsInSomeThread
{
#include "SetError.h"
bool SomeFunc1() ___try;
{
SetError(new Error(5, "SomeFunction2", "Some error from another thread", "File main.cpp"))
return true;
} ___success;
bool SomeFunc2() ___try;
{
SetError(new Error(5, "SomeFunction2", "Some error from another thread", "File main.cpp"))
return true;
} ___success;
}
And to access _Error
, you need to add the namespace of the thread
if (FunctionsInSomeThread::_ERROR.code != 0)
{
// Error handling
}
Or in case it is inside the same namespace then no need to add FunctionsInSomeThread:: before.
The idea behind this is that you can't warp the function only with ___success;
keyword. You will get compile error. So the developer will never return old error code from another function.
If you wrote ___success;
at the end of the codeblock, you must write also ___try;
at the start!
You also can't use SetError
macro if it is not wrapped in ___try;
and ___success;
.
The idea come from the AutoIt language where you have this consept:
https://www.autoitscript.com/autoit3/docs/functions/SetError.htm
So this is almost the same in C if you use this header.