tags:

views:

213

answers:

8

I'm using error codes for handling errors in my c++ project. The problem is how to return error codes from a function which is supposed to return some variable/object.

consider this:

long val = myobject.doSomething();

Here, myobject is an object of some class. If doSomething function encounters some error condition then how should it notify the caller (Without using exceptions).

Possible solutions:

  1. Have a data member (say err_) in the class which can be checked by the caller. But it would be unsafe in a multi-threaded application sharing the same object and calling the same function.
  2. Use some global error variable, again same issue in a multi-threaded environment.

Now how can I notify the caller about some error condition?

+3  A: 

You can pass variable as reference and return error code in it.

anthares
More common practice is to pass variable witch will get the result by reference and return error code.
adf88
+1  A: 

It is common to return a return/error code, and make available a property or member with the results.

int retCode = myobject.doSomething();
if (retCode < 0){ //Or whatever you error convention is
   //Do error handling
}else{
   long val = myobject.result;
}

It is also common to pass in a pointer that is set to the return value, and return the return/error code. (See HrQueryAllRows).

long val = INIT_VAL;
int retCode = myObject.doSomething(&val);

if (retCode < 0){
    //Do error handling
}else{
    //Do something with val...
}
C. Ross
A: 

Return an error handle. Have an error manager keep the error codes and additional informations (e.g. ERROR_INVALID_PARAMETER and name-value-pairs like ParameterName="pszFileName"). This information can be accessed using the handle. The caller can check the error handle against a NO_ERROR_HANDLE. If true, no error occurred. The caller can augment the error information and pass the handle up the stack. The error manager can be one for the process or one for each thread.

ur
+1  A: 

You have three options:

Create a class containing the return value and a possible error code.

Use something like boost::optional for the return value, which allows for invalid responses.

Pass a reference to a variable and return any possible error code within that.

Conor
+1  A: 

The most common practice is to return the error code

long result;
int error = some_obj.SomeMethod(&result);

or return a value that indicate there was an error:

long result = some_obj.SomeMethod();
if (result < 0) error = some_obj.GetError();
adf88
+6  A: 

Make a template called, say, Maybe that it parametrized by your return value type. Whenever you return a value, wrap it in this template like this:

Maybe<long> result = object.somemethod();

The Maybe template would have a way of being instantiated with an error code (probably a static method):

return Maybe<long>::error(code);

But ordinarily would just be returned with the value:

Maybe<long> retval;
retval = 15;
return retval;

(You would have to, of course, override the appropriate constructors, assignment operators, etc.)

In the client side you call a method to check for the error.

Maybe<long> result = object.somemethod();
if (result.is_error) 
{ 
    ... handle the error ...
}
else
{
    ... use the result ...
}

Again you'd need the appropriate operators defined to use Maybe<long> wherever there's a long required.

This sounds like a lot of work, but really the work is done once in making a good, bulletproof Maybe template. You'll also have to do some performance tuning on it to avoid nasty overheads. If you want to make it more flexible you can parametrize it on both the return value type and the error type. (This is only a minor increase in complexity.)

JUST MY correct OPINION
+1 - This is pretty elegant. You can extend it nicely by adding a cast operator to `bool` so you can write `if (result)` instead of `if (!result.is_error)` and add an exception on accessing the result value if the result is an error. I know that tossing an exception is what we are avoiding but this would really be a good case for it.
D.Shawley
I would say accessing the value when it is an error state is an ideal situation for tossing an exception, actually, since it shows obvious programmer error: not checking error returns.
JUST MY correct OPINION
@JUST: And if you think this just a bit further, you'll arrive at throwing exceptions right away instead of relying on programmers on checking return values.
sbi
As I said elsewhere on this page, exceptions are for exceptional circumstances (read: unexpected situations). Return codes are for when you expect errors as part of normal program execution. You don't use exceptions as a general purpose signalling mechanism. [Look at the first item on this list](http://www.parashift.com/c++-faq-lite/exceptions.html#faq-17.12) for some guidance. Exceptions are not return codes and should never be used as a general return code mechanism. Using them as such obfuscates code in the worst `COME FROM` kind of way **and** costs a lot.
JUST MY correct OPINION
Ah, Haskell :) IMHO, it is a great solution, but for a different problem. Your template, or Boost optional type are best used in situations where a function may or may not return a result: quering a collection is a classic example of that.
Nemanja Trifunovic
Hush @Nemanja Trifunovic! You're spoiling the joke!
JUST MY correct OPINION
Actually, @Nemanja Trifunovic, if I were to do this seriously in code I'd do an `Either<value,error>` template (which I alluded to at the end of my answer there) but the `Maybe` monad is a more recognizable name to casual Haskell users.
JUST MY correct OPINION
Fancy, but what's the typical performance cost?
Steven Sudit
It's called `boost::optional` and `boost::variant`, the runtime cost of those boost library is nearly negligible, because the values you put there are stack allocated: the templates wrap a flag indicated which value is currently stored + a `union`-like structure (maybe raw-memory correctly aligned depending on the current object).
Matthieu M.
@Matt: I'm not just being paranoid about performance; I've run into cases where more complex return types cause big slowdowns. It sounds like using a `boost::optional` or `boost::variant` would yield some flexibility, but would likely prevent optimizations such as simply returning the value in the accumulator. Whether this is an acceptable cost is something we'd have to decide after measuring it in context, of course. The alternative, which I've suggested elsewhere, is to use a thread-local errno.
Steven Sudit
@Steven Sudit: I'm certainly sorry if you thought I downreguarded your concern for performance, I certainly wasn't. `variant` has been benchmarked to be as fast as a structure holding an enum + a union, while `boost::any` is on the order of magnitude of `dynamic_cast`ing. I don't know any benchmark for Boost.Optional unfortunately, so I can't answer here.
Matthieu M.
@Matt: No, the error is mine if I made it seem like I was offended. I'm not, at all. It's good to know that `boost::variant` is fairly cheap while `boost::any` is a bit more expensive. I suspect that `boost::optional` would be comparable in performance with the former.
Steven Sudit
+6  A: 

You can use exceptions.

swegi
-1, read the question again.
adf88
Before you use an exception you need to ask "is this truly an **exceptional** situation that warrants the massive overhead increase involved in throwing an exception?"
JUST MY correct OPINION
@adf88: I just read the question, and I still think swegi hit the nail on the head. `+1` from me.
sbi
@JUST: I have yet to see a piece of software that suffers from "the massive overhead increase involved in throwing an exception" in case of an error.
sbi
"You can use exceptions" is not an answer to "how should it notify the caller (Without using exceptions)." question. Maybe if he wrote "You should use exceptions"...
adf88
@sbi: I have. It's not pretty.
JUST MY correct OPINION
@JUST: Well, so that's one single data point I have now (from 2nd-hand) in more than a decade of professionally programming C++. OTOH, I have seen so many bugs around ignored return values (with my own eyes), I can't even begin to even estimate the number of digits in that.
sbi
@adf88: swegi might not be a native speaker, and this might not sound all too different to non-natives. Down-voting based on "can" vs. "should"? Honestly.
sbi
Gonna have to agree with this one, even if the original poster doesn't like this answer. Exceptions were made to solve this problem. Exceptions are somewhat difficult to use, but it is possible to write safe multi-threaded code with them. (granted, its difficult, but anything dealing with exceptions OR multi-threaded code is difficult, let alone both).
Dragontamer5788
A: 

I would suggest following:

class foo {
public:
    long doSomething();
    long doSomething(error_code &e);
};

Where error_code is some type that holds error. It may be integer or better something based on boost::system::error_code.

And you supply two functions:

  1. First version throws the error, for example throw boost::system::system_error that is created from boost::system::error_code.
  2. Second returns the error code into e.
Artyom