0
votes

I have a function in a C++ program returning a string. On certain conditions, e.g. if the function encounters an error or so, I want to return a special value telling the caller that something has gone wrong.

I could basically just return an empty string "", but the function does need the empty string as normal return value.

  • How can I accomplish this?
  • Do I have do create a special data structure that for my function that holds a bool if the function was successfully run and a string containing the actual return value?
6

6 Answers

10
votes

This sounds like a usecase for exceptions.

try {
  std::string s = compute();
} catch(ComputeError &e) {
  std::cerr << "gone wrong: " << e.what();
}

If you don't want to or can't use exceptions, you could change the function's interface

std::string result;
if(!compute(result)) {
  std::cerr << "Error happened!\n";
}

Though most often, i've seen the return value is used for the actual result, and an error pointer is passed

bool b;
std::string s = compute(&b);
if(!b) {
  std::cerr << "Error happened!\n";
}

This has the benefit that you can default the error argument pointer to 0 and code that can ignore the error (because it could live with an empty string return, for example, or if it knows in advance the input is valid) would not need to bother:

std::string compute(bool *ok = 0) {
  // ... try to compute

  // in case of errors...
  if(ok) {
    *ok = false;
    return "";
  }

  // if it goes fine
  if(ok) {
    *ok = true;
  }
  return ...;
}
3
votes

You can definitely return a pair, although it is klunky.

pair< string, bool > my_method(...) {
  if (a) {
    return make_pair(some_value, true);
  } else {
    return make_pair("", false); // error
  }
}

pair< string, bool > result = my_method(...);
if (result.second) {
  // success
} else {
  // error
}

You can also pass either the bool or the string by reference,

bool my_method(string& s, ...) {
  ...
}

string s;
if (my_method(s, ...)) {
  // success
} else {
  // error
}

or:

string my_method(bool& ok, ...) {
  ok = false; // default
  ...
}

bool ok;
s = my_method(ok, ...));
if (ok) {
  // success
} else {
  // error
}
2
votes

You could try returning an auto_ptr to a string, but this will cost you an explicit new-ing of a string.

std::auto_ptr<std::string> Foo(int i)
{
    if(i == 0) // Error!
        return std::auto_ptr<std::string>(NULL);
    else // Works.
        return std::auto_ptr<std::string>(new string("Hello world!"));
}
0
votes

If it's really something like an error, you should throw an exception. But by reading your question I guess it's not an "exceptional behaviour"?

If that's the case, you have several non-perfect solutions :

  1. Return a structure with the string and a boolean that tells if the function failed (a simple std::pair<> could be enough).
  2. Make your function modify a string parameter provided by reference and return a boolean telling if the function failed.
  3. Make your function a functor/object that have a state. That state would be (at least) a boolean giving the failure or success of the last function call -- that would then be a function call.

3 is IMO bad design, while 2 and 1 are unperfect compromise.

0
votes

It depends on how is your program organized.

You may return an additional boolean signifying if the function succeeded. You may return a structure containing boolean and string. You may return a special string (not necessarily empty) which should represent the failure. You may throw an exception. You may set a global flag indicating an error (though I would not recommend it).

There must be lot of other methods to express function failure, too.

0
votes

The std::pair<> method is good. Another alternative is to have the caller pass the output string in as a non-const reference, and have the function return true or false depending on if an error was encountered or not.

bool Foo(int i, std::string& result)
{
    bool ret = false; // no error
    // do stuff...
    result = "blahbalhbalh";
    return ret;
}