user2175394
user2175394

Reputation: 83

What should a function return when invalid arguments are passed?

I would like to know what this get function should return when the parameters don't meet the if condition

    template <class Object>
    const Object& SparseMat<Object>::get(int c, int r) //const
    {
        if((c >= 0)&&(c <= cCapacity)&&(r >= 0)&&(r <= rCapacity))
        {
            return mObjects[c][r];
        }
        //what should I return here?
    }

Upvotes: 2

Views: 667

Answers (3)

AnT stands with Russia
AnT stands with Russia

Reputation: 320451

It is entirely up to you to decide what it should return and whether it should return at all. Maybe instead of returning it should abort ("crash") or thrown an exception? As other answers already suggested, throwing an exception might be the nest approach in this case.

However, if you really insist on returning something in response to erroneous input, one choice you have in a case like that would be a pre-defined "dummy"/"guardian" object of type Object that exists specifically for handling such situations.

template <class Object>
class SparseMat 
{
  ...
  static Object error_object;
};


template <class Object>
const Object& SparseMat<Object>::get(int c, int r) //const
{
    if((c >= 0)&&(c <= cCapacity)&&(r >= 0)&&(r <= rCapacity))
    {
        return mObjects[c][r];
    }

    return error_object;
}

Depending on the design, you might want to make that error_object easily recognizable by the calling code. Or you can design that "guardian" object so that the calling code will work properly without even realizing that the returned object is a "dummy". Again, this is up to you to decide.

Upvotes: 0

Matthieu M.
Matthieu M.

Reputation: 299810

You actually have multiple choices, especially if you are willing to change the signature.

Most likely, you want to signal an error, and exceptions are pretty interesting here:

template <class Object>
const Object& SparseMat<Object>::get(int c, int r) const
{
    if((c >= 0)&&(c <= cCapacity)&&(r >= 0)&&(r <= rCapacity))
    {
        return mObjects[c][r];
    }
    throw UnknownCoordinates(c, r, cCapacity, rCapacity);
}

Or, changing the signature, you can include the concept of nullity:

template <class Object>
Object const* SparseMat<Object>::get(int c, int r) const
{
    if((c >= 0)&&(c <= cCapacity)&&(r >= 0)&&(r <= rCapacity))
    {
        return &mObjects[c][r];
    }
    return nullptr;
}

Which can be made more explicit using boost::optional:

template <class Object>
boost::optional<Object const&> SparseMat<Object>::get(int c, int r) const
{
    if((c >= 0)&&(c <= cCapacity)&&(r >= 0)&&(r <= rCapacity))
    {
        return mObjects[c][r];
    }
    return boost::none;
}

Or, without changing the signature, you might wish to use a null object however this is hardly ever the best choice (it restricts you to objects that embed a concept of nullity, and such objects are better refactored not to have a nullity concept and instead rely on boost::optional<Object>)

template <class Object>
const Object& SparseMat<Object>::get(int c, int r) const
{
    if((c >= 0)&&(c <= cCapacity)&&(r >= 0)&&(r <= rCapacity))
    {
        return mObjects[c][r];
    }
    return null; // where null is "static Object const null;" for example.
}

Upvotes: 4

David G
David G

Reputation: 96810

You should throw an exception:

#include <stdexcept>

throw std::out_of_range("Indexes are out of range");

Upvotes: 11

Related Questions