13

I like the feature in Python that can return None when it doesn't find the correct return value. For example:

def get(self, key):
    if key in self.db:
        return self.db[key]
    return None

I need to implement the same feature in C++. I think about some possibilities.

Return true/false, when true get the value from reference or pointer

bool get(string key, int& result)
{
    if (in(key, db)) {
        result = db[key];
        return true;
    }
    return false;
}

Throw an error for notifying None case

int get(string key) throw (int)
{
    if (in(key, db)) {
        result = db[key];
        return result;
    }

    throw 0;
}

try {
    ....
}
catch (int n)
{
    cout << "None";
}

Use pair

pair<bool, int> getp(int i)
{
    if (...) {
        return pair<bool, int>(true, 10);
    }
    return pair<bool,int>(false, 20);
}

pair<bool, int> res = getp(10);
if (res.first) {
    cout << res.second;
}

Which one is normally used in C++? Are there any other ways to do it in C++?

prosseek
  • 182,215
  • 215
  • 566
  • 871
  • 8
    Use `boost::optional` and switch to `std::optional` in C++14 if that logic fits in. I'd say it's the most similar to the Python code, but with different languages come different idioms. – chris Jun 13 '13 at 22:59

5 Answers5

17

The normal C++ way to do this (note: C++ is not Python) is to return iterators from such functions and return end() when the item can't be found.

If you wish to use non-iterator return values however, use boost::optional and return boost::none when you would return Python's None.

Definitely don't use throw unless you expect to never have the error case during normal execution.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • 4
    However, if the case shouldn't happen during normal execution, _Please_ use `throw`. – Mooing Duck Jun 14 '13 at 00:37
  • @MooingDuck some ppl like me dont like using exceptions for this.. https://blogs.msdn.com/b/ericlippert/archive/2008/09/10/vexing-exceptions.aspx?Redirected=true – NoSenseEtAl Jun 14 '13 at 07:56
  • 1
    Fact i hope someone finds interesting. c++ standard utilizes somewhat similar to the `pair` return type approach. Look 1-2) of [map::insert](http://en.cppreference.com/w/cpp/container/map/insert). But they did it probably because flagging via `Iterator` was unsuitable there. I guess `pair` can be useful if you can't use iterator way (e.g. return some default element). – luk32 Jun 14 '13 at 10:52
  • @luk32: That's not _quite_ the same, because both elements of the pair returned by `map::insert` are valid. That's not a signaling a failure,the bool merely tells you if the element was inserted or if it was already there. Not an error in either case. – Mooing Duck Jun 14 '13 at 16:48
  • @MooingDuck I am aware of that, "somewhat similar" being the keywords. I also said flagging via value was unsuitable, precisely because every returned value shall be a "valid" object there. Still, I think you cannot deny the fact they do signal something via return-pair-bool method. One can signal whatever they want, what's wrong with it? I also do not think you can say OP wants to an signal error. I find this too strong. If it were the case an exception would be better choice. It is anticipated and valid use-case. My point was not to say they do the same, but fact they use the same technique. – luk32 Jun 16 '13 at 14:59
  • 1
    @luk: While the OP _could_ use that method certainly, `boost::optional` is a better design for that option. In the C++ standard library, "none" is always signaled by an iterator to the end, or an exception (actually, I can think of one case where `NULL` is returned). But _never_ does the C++ standard library signal "no value" via a `pair`. – Mooing Duck Jun 16 '13 at 15:38
3

I achieved the good/bad return value using a small custom Checked templated class. My actual class was a little more comprehensive, including assignment operators, error reason strings and specialisations for reference types, et cetera, which is why I didn't use boost::optional<T>. I could publish the full class if there is interest.

The general gist of the class is this:

static const class Bad {} None;

template<typename ValueType>
class Checked
{
public:
    // Constructor for good value.
    Checked(ValueType x)
        : value(x), valid(true)
    {}

    // Constructor for bad value.
    Checked(Bad)
        : value(), valid(false)
    {}

    operator ValueType(void) const
    {
        if (!valid)
            ;//assert or throw...

        return value;
    }

    ValueType value;
    bool valid;
};

This can be used like so:

Checked<int> Divide(int numerator, int denominator)
{
    if (denominator == 0)
        return Bad(); // or None;

    return numerator / denominator; // Automatically uses the "good value" constructor
}

or:

Checked<int> result = Divide(4, 5);
if (result.valid)
    std::cout << result; // or result.value
else
    std::cout << "Bad!";

This approach is often more efficient than the reference approach because of return value optimisation.

Timotheos
  • 405
  • 3
  • 8
1

I think different projects in C++ use different standards, but Return true/false you mentioned could be the most common way in C++, although some people prefer to return false on success while the others return true on success. In other cases, if the value you would like to get is a pointer, then returning null is another common way in C++.

For example, if you're working on Microsoft related projects, then the most common way is to return HRESULT, which is a return type introduced by Microsoft.

In linux, functions usually return 0 on success, and non-zero value indicates error code. (you may find this discussion helpful).

Community
  • 1
  • 1
keelar
  • 5,814
  • 7
  • 40
  • 79
1

I would say that those three methods are all very common in C++.

It goes without saying that if the return type already can have some sort of "invalid" or "zombie" state (e.g., like a NULL pointer or a NaN number), then that might just be the easiest thing to use.

The "take output-parameter by reference and return an error-code" is the more traditional C-style way of doing things, which is, of course, very common. The tradition is to return 0 on success and some error-code on failure (any non-zero value).

The "throw an exception if you can't return a value" generally makes sense if you adopt exceptions in your code. This is very common, but not universally accepted (not everyone likes or uses exceptions for the same purposes).

Those first two options are in a never-ending feud (i.e., error-codes vs. exceptions), and it really depends on which side you pick. So, I would refer you to that debate (which is too subjective for StackOverflow, of course).

The "return a pair of bool and value" is, I would say, less common, but still I've seen this many times. With the adoption of tuples (boost::tuple or std::tuple (C++11)) and with the use of tiers (boost::tie or std::tie (C++11)), the whole idea of returning multiple values from a function (like many languages allow) is ever more attractive and used in practice.

Among other options, you have boost::optional<T>, whose name is pretty self-explanatory (basically, the third option (pair) wrapped in a prettier package). And you might also have Alexandrescu's Expected template, which gives you a hybrid of all three options such that you get a return value bundled with a flag to know if it is valid or not, and bundled with an exception describing why it couldn't produce the value, which would be automatically thrown if you attempt to read the invalid value. However, the template requires C++11 features to work.

Mikael Persson
  • 18,174
  • 6
  • 36
  • 52
1

When returning pointer, I can use reinterpret_cast for NULL return.

class A
{
};

A* a(int i)
{
    if (i == 0) return new A();
    return reinterpret_cast<A*>(NULL);
}
int main(int argc, char *argv[]) {
    A* result = a(1); // result is NULL
    if (result == NULL) {
        cout << "NULL returned";
    }
    result = a(0);
    if (result != NULL) {
        cout << "NON NULL returned";
    }
}
prosseek
  • 182,215
  • 215
  • 566
  • 871