I have inherited a (large) piece of code which has an error tracking mechanism where they pass in a boolean variable to all the methods they call and on errors at various stages of execution the method is stopped and returns, sometimes a default value.
Something like (BEFORE):
#include <iostream.h>
int fun1(int par1, bool& psuccess)
{
if(par1 == 42) return 43;
psuccess = false;
return -1;
}
int funtoo(int a, bool& psuccess)
{
int t = fun1(a, psuccess);
if(!psuccess)
{
return -1;
}
return 42;
}
void funthree(int b, bool& psuccess)
{
int h = funtoo(b, psuccess);
if(!psuccess)
{
return;
}
cout << "Yuppi" << b;
}
int main()
{
bool success = true;
funthree(43, success);
if(!success)
{
cout<< "Life, universe and everything have no meaning";
}
}
Please note, that this is a mixture of C and C++ code, exactly the way the project is in.
Now, comes a piece of C magic: "someone" somewhere defined a macro:
#define SUCCES_OR_RETURN if(!psuccess) return
And the program above becomes (AFTER):
#include<iostream.h>
int fun1(int par1, bool& psuccess)
{
if(par1 == 42) return 43;
psuccess = false;
return -1;
}
int funtoo(int a, bool& psuccess)
{
int t = fun1(a, psuccess);
SUCCES_OR_RETURN -1;
return 42;
}
void funthree(int b, bool& psuccess)
{
int h = funtoo(b, psuccess);
SUCCES_OR_RETURN ;
std::cout << "Yuppi" << b;
}
int main()
{
bool success = true;
funthree(43, success);
if(!success)
{
cout<< "Life, universe and everything have no meaning";
}
}
The question: I am wondering if there is a nicer way to handle this kind of error tracking or I have to live with this. I personally don't like the abuse of the C macro SUCCES_OR_RETURN ie. that once it is called with a parameter, and in other cases it is called without, feels like a real return statement, but I did not find any better solutions to this ancient design.
Please note that due to platform restrictions we have several restrictions, but regardless of it I am willing to hear opinions about these two:
throwing exceptions. The code is a mixture of C and C++ functions calling each other and the compiler sort of does not support throw (accepts in the syntax but does nothing with it, just a warning). This solution is sort of the standard way of solving this problem in a C++ environment.
C++11 features, this goes to a tiny embedded platform with an obscure and ancient "almost" C++ compiler which wasn't made to support the latest C++ features. However for future reference I am curios if there is anything C++11 offers.
template magic. The compiler has problems understanding complex templated issues, but again I am willing to see any solutions that you can come up with.
Edit
Also, as #BlueMoon suggested in the commend, creating a global variable is not working since at a very beginning of the function chain calling the success variable is a member variable of a class, and there are several objects of this class created, each of them needs to report its success status :)
There's a great breakdown of hybrid C and C++ error handling strategies here:
http://blog.sduto.it/2014/05/a-c-error-handling-style-that-plays.html
To quote the linked article, your options largely boil down to:
Return an error code from functions that can fail.
Provide a function like Windows's GetLastError() or OpenGL's glGetError() to retrieve the most recently occurring error code.
Provide a global (well, hopefully, thread-local) variable containing the most recent error, like POSIX's errno.
Provide a function to return more information about an error, possibly in conjunction with one of the above approaches, like POSIX's strerror function.
Allow the client to register a callback when an error occurs, like GLFW's glfwSetErrorCallback.
Use an OS-specific mechanism like structured exception handling.
Write errors out to a log file, stderr, or somewhere else.
Just assert() or somehow else terminate the program when an error occurs.
It seems like the author of the code you have inherited picked a rather strange way, passing a pointer to a boolean [sic] for the function to work with seems rather unusual.
The article has some great examples, personally I like this style:
libfoo_widget_container_t container = NULL;
libfoo_error_details_t error = NULL;
if (libfoo_create_widgets(12, &container, &error) != libfoo_success) {
printf("Error creating widgets: %s\n", libfoo_error_details_c_str(error));
libfoo_error_details_free(error);
abort(); // goodbye, cruel world!
}
Here you get a bit of everything, passed in pointer to error type, a comparison against a success constant (rather than 0|1, a painful dichotomy between C and the rest of the world!).
I don't think it would be too much of a push to say that your macro could rather better be implemented with a goto, in any case, if a function is calling SUCCES_OR_RETURN more than once, it might be a clue that the function is doing too much. Complex cleanup, or return might be a code smell, you can read more here http://eli.thegreenplace.net/2009/04/27/using-goto-for-error-handling-in-c/
I have seen this style of error handling before. I call it error-oblivious manual pseudo-exceptions.
The code flow is mostly error-oblivious: you can call 3 functions in a row with the same error flag, then look at the error flag to see if any errors have occurred.
The error flag acts as a pseudo-exception, where once set we start "skipping" over normal code flow, but this is done manually instead of automatically.
If you do something and do not care if an error occurs, you can just drop the error produced and proceed on.
The ICU library handles errors in a similar way.
A more C++1y way to do this while minimizing structural differences would be to modify code to return an expected object.
An expected<T, Err> is expected to be a T, and if something went wrong it is instead an Err type. This can be implemented as a hybrid of boost::variant and C++1y's std::optional. If you go and overload most arithmetic operations on expected< T, Err > + U to return expected< decltype( std::declval<T&>() + std::declval<U>(), Err > and did some careful auto, you could allow at least arithmetic expressions to keep their structure. You'd then check for the error after the fact.
On the other hand, if the error return values are predictable based on their type, you could create a type that when cast to a given type produced an error value. Modify functions returning void to return an error object of some kind while you are at it. And now every function can
if (berror) return error_flag_value{};
which at least gets rid of that strange ; or -1; issue.
If you want to go full C++, the answer would be changing the "invalid return values" for exceptions...
#include <iostream>
#include <exception>
using std::exception;
struct error : exception { const char* what() const throw() override { return "unsuccessful"; } };
int fun1(int par1) {
if( par1 == 42 ) return 43;
throw error();
}
int funtoo(int a) {
fun1(a);
return 42;
}
void funthree(int b) {
funtoo(b);
std::cout << "Yuppi " << b << "\n";
}
int main() {
try {
funthree(42);
} catch(exception& e) {
std::cout << "Life has no meaning, because " << e.what() << "\n";
}
}
This prints Yuppi 42 (if you change the call funthree(42) for funthree(43) it prints Life has no meaning, because unsuccessful...)
(live at coliru)
Related
I have a function that returns a double. Any real number is a valid output. I'm using nan's to signal errors. I am error checking this way.
double foo();
const auto error1 = std::nan("1");
const auto error2 = std::nan("2");
const auto error3 = std::nan("3");
bool bit_equal(double d1, double d2) {
return *reinterpret_cast<long long*>(&d1) == *reinterpret_cast<long long*>(&d2);
}
const auto value = foo();
if(std::isnan(value)) {
if (bit_equal(value, error1)) /*handle error1*/;
else if (bit_equal(value, error1)) /*handle error2*/;
else if (bit_equal(value, error1)) /*handle error3*/;
else /*handle default error*/;
} else /*use value normally*/;
Alternatively, if the compiler support has caught up, I can write it this way
double foo();
constexpr auto error1 = std::nan("1");
constexpr auto error2 = std::nan("2");
constexpr auto error3 = std::nan("3");
constexpr bool bit_equal(double d1, double d2) {
return std::bit_cast<long long>(d1) == std::bit_cast<long long>(d2);
}
const auto value = foo();
if(std::isnan(value)) {
if (bit_equal(value, error1)) /*handle error1*/;
else if (bit_equal(value, error1)) /*handle error2*/;
else if (bit_equal(value, error1)) /*handle error3*/;
else /*handle default error*/;
} else /*use value normally*/;
Or even
double foo();
constexpr auto error1 = std::bit_cast<long long>(std::nan("1"));
constexpr auto error2 = std::bit_cast<long long>(std::nan("2"));
constexpr auto error3 = std::bit_cast<long long>(std::nan("3"));
const auto value = foo();
if(std::isnan(value)) {
switch(std::bit_cast<long long>(value)) {
case error1: /*handle error1*/; break;
case error1: /*handle error2*/; break;
case error1: /*handle error3*/; break;
default: /*handle default error*/;
}
} else /*use value normally*/;
I have to do this because comparing nan's with == always returns false.
Is there a standard function to perform this comparison in C++?
Are any of these 3 alternatives better than the others? Although the last option seems the most succinct, it requires me to do return std::bit_cast<double>(error1); inside foo() rather than just return error1;.
Is there a better design where I can avoid using nan as an error value?
Is there a better design where I can avoid using nan as an error value?
Yes.
Throw an exception.
Use a struct (or tuple, not really) as return value
Use an out ref parameter
Since there are better alternatives, I don't think it's worth answering question 1. and 2.
NaN error signaling
Returning NaNs as error indicators is certainly a valid design choice. If you write numeric code, I'm sure you will find many people who get annoyed when you throw exceptions on any invalid input instead of letting the error propagate through NaNs. "When in Rome, speak like the Romans", right? When in math, speak like the math.h functions ;-)
(Of course this depends on your use case and the expectations of your API users)
However, NaN payloads aren't that good. Using them as an error "hint" may work for you, so you can look at the payload in a data dump and find out where it came from. But as you certainly have noticed, there is no predefined inverse to nan(const char*). Also, NaN payloads tend not to propagate well. For example, while most math functions will return a NaN when they received a NaN input, they will give you a new one without the payload.
There is a good article by agner.org talking about this very topic: Floating point exception tracking and NAN propagation
My personal recommendation would be:
Keep returning NaN on error because it is fast to check
Keep using payloads as error hints
Use a different mechanism to signal the specific type of error
Alternative mechanisms
Options that come to mind:
Exceptions. Maybe paired up with a non-throwing variant for users that are content with just a NaN
double foo();
double foo(std::nothrow_t) noexcept;
double bar()
{
try {
double x = foo();
} except(const std::domain_error&) {
error();
}
double y;
if(std::isnan(y = foo(std::nothrow)))
error();
}
Optional error code or struct output argument: double foo(Error* error=nullptr). After the call, check for NaN. If NaN, read exact error from error struct. If the user is not interested in the exact error, they don't pass a struct to begin with
struct Error
{
int errcode;
operator bool() const noexcept
{ return errcode; }
/** throw std::domain_error with error message */
[[noreturn]] void raise() const;
void check() const
{
if(errcode)
raise();
}
}
double foo(Error* err=nullptr) noexcept;
double bar()
{
Error err;
double x;
x = foo(); // just continue on NaN
if(std::isnan(x = foo()))
return x; // abort without error explanation
if(std::isnan(x = foo(&err)))
err.raise(); // raise exception
return x;
}
std::variant<double, Error> return value. In my opinion the API is not well suited for this; too verbose. This will be fixed in C++23 with std::expected. Also less efficient because the data will likely be returned on the stack
std::pair<double, Error>. If the Error type is a simple struct without a destructor and with a maximum size of 8 byte or a primitive type (so it can be returned in a register), this will be very efficient and it is also easy to check. Building your own custom pair-like type that offers some convenience methods like get_result_or_throw_error() is also possible.
template<class T>
struct Result
{
T result;
Error err;
Result() = default;
explicit constexpr Result(T result) noexcept
: result(result),
err() // set to 0
{}
explicit constexpr Result(Error err, T result=NAN) noexcept
: result(result),
err(err)
{}
operator bool() const noexcept
{ return err; }
T check() const
{
err.check(); // may throw
return result;
}
bool unpack(T& out) const noexcept
{
if(err)
return false;
out = result;
return true;
}
};
Result<double> foo() noexcept;
double bar()
{
double x = foo().check(); // throw on error
double y = foo().result; // ignore error. Continue with NaN
}
Result<double> baz() noexcept
{
Result<double> rtrn;
double x;
if(! (rtrn = foo()).unpack(x))
return rtrn; // propagate error
rtrn.result = x + 1.; // continue operation
return rtrn;
}
Further discussion
To give a bit more of a personal opinion and also delve into a few more performance concerns:
Exceptions
Well, all the usual aspects of exception handling and when to use them apply. See for example When and how should I use exception handling?
I think at this point the general consensus on exceptions is that they should not be part of the regular control flow and should only be used for very rare, exceptional cases where you most likely want to abort the operation instead of, say mitigating the error. It is just too easy to forget catching exceptions on all call sites so they tend to travel very far up the call chain before being caught.
So their use is very situational. Do you want your users to explicitly deal with any error condition on the site where they appear? Then don't use exceptions because users of your API will definitely not be bothered using a try-except block everywhere. If you want the error to get out of the way as far as possible, use them.
As for the idea of using a second set of functions without exceptions: Well, it doesn't compose well. It's feasible for a small set of functions but do you really want to write every piece of code twice, once with and once without exceptions? Probably not.
Error output parameter
This is probably the most flexible option while remaining very efficient. Passing an additional parameter has a minor cost but it isn't too bad.
The main benefit is that this is the only option besides exceptions that allows you to compose complex error reports with dynamic memory allocation for error messages etc. without incurring extra costs in the no-error case. If you make the Result object complex enough to require a destructor, it will be passed on the stack and you need to re-read the error code and actual result value after every function call and then its destructor will run.
In contrast, the Error object will be rarely touched. Yes, its destructor will run once it goes out of scope. However, I expect that most code bases will have one error object very far up the call chain and then just pass it down and reuse that object as needed.
If you make the Error object complex you might find yourself in a situation where a caller wants the error code but not the error message, e.g. because they expect an error and want to mitigate it instead of reporting it. For this case, it might make sense to add a flag to the object to indicate that the error message should not be filled.
struct Error
{
int errcode;
bool use_message;
std::string message;
};
variant, expected
I think I've made it sufficiently clear above that I don't think std::variant has a suitable API for this task. std::expected may one day be available on every platform you target but right now it isn't and you will definitely draw the ire of your release engineers if you start using C++23 features and they have to build your code for RHEL-8 or something similarly long-lived.
Performance-wise all the points I discuss below for Result apply. In addition, the floating point result will always be returned either on the stack or in a general purpose register. Using the Result or std::pair approach will at least get double results in a floating point register on Mac/Linux/BSD, which is a minor advantage, but not huge. floats will still be packed in a GP register, though.
Result type
From an API design perspective, the nice thing about a Result object is that the caller cannot ignore the possibility of an error. They may or may not remember to check for NaN or catch exceptions but with Result, they always have to unpack the contained value and in doing so, decide on their desired error handling.
From a performance perspective, the main point when writing a Result type is that you don't want to make it more expensive to access the actual return value unless you don't care about runtime and code size. This means making sure the return value can be passed in registers instead of the stack.
On Windows this is very hard to achieve because the Windows calling convention only uses a single register for return objects and I don't think they pack two 32 bit values into one 64 bit register. At this point your only options are a) accept the cost of stack return values b) try to pack error code and result value in one scalar like you did with NaN payloads or other tricks like negative integers c) not use this approach.
On all other major x86-64 platforms, you have two registers to work with. This is far more feasible unless you regularly return 16 byte payloads like std::complex<double>.
However, for this to work, the Result must not have a non-trivial destructor or copy/move constructor. For all intents and purposes, this means you cannot have dynamic error messages in the Error type. There are ways around this, if you absolutely need: You enforce that every access to the actual result also checks the error and deallocates, either reporting or ignoring it in the process. Use [[nodiscard]] on the return values to ensure the return value is checked at all. This works, for example:
struct Error
{
std::string* message;
private:
[[noreturn]] static void raise_and_delete_msg(std::string*);
public:
/*
* Note: clang needs always_inline to generate efficient
* code here. GCC is fine
*/
[[noreturn, gnu::always_inline]] void raise() const
{ raise_and_delete_msg(message); }
void discard() const noexcept
{ delete message; }
operator bool() const noexcept
{ return message != nullptr; }
void check() const
{
if(message)
raise();
}
};
template<class T>
class Result
{
T result;
Error err;
public:
constexpr Result()
: result(),
err()
{}
explicit Result(T result)
: result(std::move(result)),
err()
{}
/** Takes ownerhip of message. Will delete */
explicit Result(std::unique_ptr<std::string>&& message)
: err(Error{message.release()})
{}
Result(std::unique_ptr<std::string>&& message, T invalid)
: result(std::move(invalid)),
err(Error{message.release()})
{}
T unchecked() noexcept
{
err.discard();
return std::move(result);
}
T checked()
{
err.check();
return std::move(result);
}
bool unpack(T& out) noexcept
{
if(err) {
err.discard();
return false;
}
out = std::move(result);
return true;
}
};
[[nodiscard]] Result<double> foo();
double bar()
{
return foo().checked() + 1.;
}
However, at this point you quickly reach the point where you exceed the 8 bytes you can reasonably use for sizeof(Error) before you go back to stack return values so I'm not sure this is worth it. For example if you want and error code plus message, you need to dynamically allocate both or do other fancy tricks. Plus, [[nodiscard]] is only a warning, so you can still easily get memory leaks.
Conclusion
If I have to make suggestions:
Use exceptions if a) they are in line with the coding style and API you normally use plus b) the expectations that both you and your API users have on these functions and c) failure should be rare, costly, and loud
Use Error output arguments if you primarily target Windows or if you want complex error reporting with dynamic messages or similar.
Use Result for simple error codes on Linux/Mac or if you want your API users to always make a conscious decision to check or ignore an error. In that case, you may also accept the additional runtime cost associated with complex Error objects or any such object on Windows.
I am currently building an embedded system and use a modern C++ compiler.
While I could technically fit exception handling in the given resources (ARM7, more than 10M RAM), I don’t think exceptions are the right tool for something like this and using exceptions requires RTTI, which in turn results in code bloat.
To stay C++-ish anyway I want to use std::error_code (or similar with more data) because I do like the concept.
However, there does not seem to be any consenus on how to actually use them. I have seen at least four different ways of passing them between function calls, two of them with multiple semantics.
Passing by pointer as an argument
void somefunction(Args..., std::error_code* error);
This is the way I have not seen that often and the one I dislike the most. It leaves the return type fully available and (often, but not always) passing nullptr resulted in normal throwing behaviour.
Passing by reference as an argument
void somefunction(Args..., std::error_code& error);
This is the one I prefer. It leaves returnvalue fully available and makes clear that the error_code is not optional.
Returning it by value
std::error_code somefunction(Ret& out <= if used, Args...);
I have seen this one quite often but don’t really like it that much, as it uses up your return value and I generally don’t like “out parameters” unless there’s no way around them.
Returning a std::variant<Ret, std::error_code>
std::variant<Ret, std::error_code> somefunction(Args...);
This one allows for a return value, but makes accessing both value and error harder. Also, it makes code calling the function more verbose.
Semantics
I have seen both way 1 and 2 with different semantics, if the error_code is passed.
Clear at start and set on error
Only set on error
Return right at start if the error_code is “set”
The last way is pretty good if you want to reduce error checking in the calling code. As you can just pass one error_code to multiple functions without checking in between and everything after the first error will not execute, similar to how exceptions would do it.
I personally do prefer way 2 with checking and returning, however I might be biased.
Is there some recommended / generally accepted way to do it?
Ok, this is no complete answer and actually not perfectly on topic because I am not aware of a standard way to do this. But I once saw a nifty little trick to make error codes harder to misuse. Consider the following code:
struct MyEC {
MyEC() {}
MyEC(MyEC && other) : parent(&other) {
// Maybe log and or abort if other is not checked
other.checked = false;
}
// Delete other constructors and assignment operators
~MyEC() {
if(!checked && parent == nullptr) {
// log and or abort
}
}
[[nodiscard]] std::error_code check() {
checked = true;
return ec;
}
void set(std::error_code err) {
if(parent == nullptr) ec = err;
else parent->set(err);
}
private:
MyEC* parent = nullptr;
checked = true;
std::error_code ec {};
};
int foo(MyEC&& err) {
err.set(/* some error */);
return 5;
}
int foo1(MyEC&&) {
return 4;
}
void bar() {
MyEC err;
foo(std::move(err));
// err has the error code and if its not checked, we will know
foo1(std::move(err));
// even though no error occurs, we will abort if err is not checked.
}
It will even then abort, when the error code is not set but also not checked, which is pretty nice. It has a lot of uses after move, which is a bit weird, but this is no problem here.
I struggle to set up clang-format to allow short lines for such format,
ierr = fun(); CHKERRQ(ierr);
clang-format break the line, as result
ierr = fun();
CHKERRQ(ierr);
It is a solution to stop clang-fromat to break short lines? Or this is in principle wrong idea to format code like this. Any advice very appreciated.
EDIT: Following Guillaume answer
In fact, I have a slightly more complex problem, where errors codes of different types are returned by two libraries, in particular, PETSc and MoAB. Also, this system has own error codes, which need to be handled. All without compromising efficiency.
struct ErrorCheckerCode {
inline void operator<<(const MoFEMErrorCode err) {
if (PetscUnlikely(err)) {
// Handle & thorw PETSc/MoFEM error
}
return;
}
inline void
operator<<(const moab::ErrorCode err) {
if (PetscLikely(MB_SUCCESS != err)) {
// Handle & trow MOAB error
}
return;
}
static const char *fUNC;
static const char *fILE;
static int lINE;
};
struct ErrorCheckerFunction {
inline ErrorCheckerCode operator<<(const char *func) {
ErrorCheckerCode::fUNC = func;
return ErrorCheckerCode();
}
};
struct ErrorCheckerFile {
inline ErrorCheckerFunction operator<<(const char *file) {
ErrorCheckerCode::fILE = file;
return ErrorCheckerFunction();
}
};
struct ErrorCheckerLine {
inline ErrorCheckerFile operator<<(int line) {
ErrorCheckerCode::lINE = line;
return ErrorCheckerFile();
}
};
And definition follows this:
#define CHKERR \
ErrorCheckerLine() << __LINE__ << __FILE__ << PETSC_FUNCTION_NAME <<
So at the end I can handle errors like this
CHKERR fun_moab();
CHKERR fun_petsc();
CHKERR fun_mofem();
This implementation is essential, so it has to be done optimally, I wonder if that can be done in simpler, more efficient way. Criticism or advice is very welcome.
Note:
As a commend. It is funny how formatting of code triggers this type of developments.
I use clang-format a lot and I don't think it can achieve this kind of formatting.
I've encountered this pattern a lot in libraries using OpenGL and DirectX. You have a API with error codes or an error stack like in OpenGL and every function might fail or issue a warning. You want your code to be optimized in release and still have a debug mode to find preciselly where things went wrong in case you spot a bug.
Some libraries provide some kind of error callback that you can set and will effectively be called each time there is a relevent error.
In case you want something more customized or no error callback is provided, you can write a simple wrapper that does a systematic error checking and warnings logging.
With these solutions you can even implement some mechanism to activate the debugging at runtime.
Now, if you are writing the library or functions that return errors returned this way, you might want to include the debug mode directly in the library with the debug callback strategy.
Now, if you want to stick to the macro solution, you could do the following:
struct ErrorChecker
{
ErrorChecker& operator << (int ierr)
{
// Error checking code
return *this;
}
};
#define CHKERR ErrorChecker() <<
and then
CHKERR fun();
I was trying to answer this question. As suggested by the accepted answer, the problem with that code is that not all control paths are returning a value. I tried this code on the VC9 compiler and it gave me a warning about the same. My question is why is just a warning and not an error? Also, in case the path which doesn't return a value gets executed, what will be returned by the function (It has to return something) ? Is it just whatever is there on top of the stack or is the dreaded undefined behavior again?
Failing to return a value from a function that has a non-void return type results in undefined behaviour, but is not a semantic error.
The reason for this, as far as I can determine, is largely historical.
C originally didn't have void and implicit int meant that most functions returned an int unless explicitly declared to return something else even if there was no intention to use the return value.
This means that a lot of functions returned an int but without explicitly setting a return value, but that was OK becase the callers would never use the return value for these functions.
Some functions did return a value, but used the implicit int because int was a suitable return type.
This means that pre-void code had lots of functions which nominally returned int but which could be declared to return void and lots of other functions that should return an int with no clear way to tell the difference. Enforcing return on all code paths of all non-void functions at any stage would break legacy code.
There is also the argument that some code paths in a function may be unreachable but this may not be easy to determine from a simple static analysis so why enforce an unnecessary return?
I would guess it is only a warning because the compiler cannot always be 100% sure it is possible to not hit a return.
i.e. if you had:
-= source1.c =-
int func()
{
if(doSomething())
{
return 0;
}
}
-= source2.c =-
int doSomething()
{
return 1;
}
The compiler in this case might not be able to know it will always hit the return, but you do. Of course this is terrible programming practice to rely on knowing how external code works.
As for what will actually be returned it depends on the platform. On x86 ABIs EAX is used for the return value (up to 32bits) so it will return what ever was placed in that register (which could be a return from something else, a temporary value or total garbage).
Technically it is not guaranteed to be an error if you call a function and that function always throws an exception. For example here is some pseudo code, and you know raiseError always throws.
MyClass func( params )
{
if( allIsValid() )
{
return myObject;
}
else
{
raiseError( errorInfo );
}
}
If the compiler cannot see the implementation of raiseError, it will not know that the function is going to throw. So really there is actually no undefined behaviour here. Of course it is good to silence the compiler here, which you can do with either writing a "dummy" return statement after raiseError, or a dummy "throw". I call them "dummy" because they will never be reached in reality. (You can also suppress the warning if you really insist). However there is no error or undefined behaviour.
here is another reason it isn't an error
the following will give you the same warning since the compiler expects you to return something from the catch block even though you're throwing there
int foo(){
try{
return bar(0);
} catch(std::exception& ex){
//do cleanup
throw ex;
}
}
int bar(unsigned int i){
if(i == 0){
throw std::string("Value must be greater than 0");
} else{
return 0;
}
}
Another example where it may be okay for some control paths to not return a value:
enum E : int {A, B};
int foo(E e) {
switch (e) {
case A: return 30;
case B: return 50;
}
}
It's possible that e won't be A or B, but the implication is that it always will be one of those values. If that's the case then the code is fine and there's no problem. Making this warning into a mandatory error would require unnecessary, 'unreachable' clutter.
If you want the warning to be an error anyway, you can configure your compiler to do that with a flag like /WX or -Werror. Though of course you should note that different compilers may make different determinations as to what's unreachable so you may be fixing different things for different compilers.
It is not an error because it may be the intended behaviour. For example, some encryption libraries use uninitialized local data as a step for seeding. As return values are kept in calling-convention and platform specific locations, this may help in some unusual (like the above) situations. In this case, the function returns whatever is left on the register used to return the return value.
Consider the following scenario:
UINT GenderID(GENDER gender)
{
switch(gender)
{
case MALE:
return MALE_ID;
case FEMALE:
return FEMALE_ID;
}
// default not required because [GENDER] in our 'Matrix' CAN be either M or F
}
a C++ complier should let you have your 'Matrix' your way; Thus its not an Error.
What is a good way to return success or one or more error codes from a C++ function?
I have this member function called save(), which saves to each of the member variables, there are at least ten of these member variables that are saved-to, for the call to save(), I want to find out if the call failed, and if so, on which member variable (some are hard failures, some are soft).
You can either return an object that has multiple error fields or you can use 'out'parameters.
How you do this depends on your design and what exactly you are trying to return back. A common scenario is when you need to report back a status code along with a message of sorts. This is sometimes done where the function returns the status code as the return value and then returns the message status via an 'out' parameter.
If you are simply returning a set of 'codes', it might make more sense to construct a struct type and return that. In that case, I would be prone to pass it in as an out parameter and have the method internally update it instead of allocating a new one each time.
Are you planning on doing this once or many times?
I know this doesn't really answer your question, but...
In C++ you should use exceptions instead of returning error codes. Error codes are most commonly used by libraries which don't want to force the library user to use a particular error handling convention, but in C++, we already have stdexcept. Of course, there might be reasons you don't use exceptions, such as if you're writing embedded code or kernel extensions.
I usually use a boost::tuple:
typedef boost::tuple<int,int> return_value;
return_value r = my_function();
int first_value = boost::get<0>( r );
int second_valud = boost::get<1>( r );
EDIT
You can also use boost::tie to extract the values from a tuple:
boost::tie( first_value, second_value ) = r;
The simplest way to return two values is with the std::pair<> template:
I would use a bitset if you're intention is to purely return error states. e.g.
const bitset<10> a_not_set(1);
const bitset<10> b_not_set(2);
const bitset<10> c_not_set(4);
...
bitset<10> foo(T& a, T& b, T& c, ...)
{
bitset<10> error_code = 0;
...
if ( /* a can't be set */ )
{
error_code |= a_not_set;
}
...
if ( /* b can't be set */ )
{
error_code |= b_not_set;
}
...
// etc etc
return error_code;
}
bitset<10> err = foo(a, b, c, ... );
if (err && a_not_set)
{
// Blah.
}
You need to return them as output parameters:
bool function(int& error1, int& error2, stringx& errorText, int& error3);
You can use an integer with bit manipulation (aka flags).
I probably try to throw an exception first but it depends on your coding paradigm. Please check some books or articles about reasons why c++ exception handling might be better.
If I really need to stick to retrun-error-code style, I would define a eunm type for specifying errors with bit operations..
enum error
{
NO_ERROR = 0,
MEMBER_0_NOT_SAVED = 1,
MEMBER_1_NOT_SAVED = 1 << 1,
MEMBER_2_NOT_SAVED = 1 << 2,
// etc..
};
int save()
{
int ret = NO_ERROR;
// fail to save member_0
ret |= MEMBER_0_NOT_SAVED;
// fail to save member_1
ret |= MEMBER_1_NOT_SAVED;
// ....
return ret;
}
int main(void)
{
int ret = save();
if( ret == NO_ERROR)
{
// good.
}
else
{
if(ret & MEMBER_0_NOT_SAVED)
{
// do something
}
if(ret & MEMBER_1_NOT_SAVED)
{
// do something
}
// check the other errors...
}
}
This is just a rough example. It's better to put this into a class or use a namespace.
I am not familiar with the internals and constrains of your project, but if possible, try to use exceptions instead of error codes.
The reasons are listed here, at C++ FAQ lite, and they conclude with:
So compared to error reporting via return-codes and if, using try / catch / throw is likely to result in code that has fewer bugs, is less expensive to develop, and has faster time-to-market.