6

I have a problem that when I use something like this:

const MyList& my_list = getListForThisRegion(/*region ID, ...*/);

I dont know what to return when no value is found.

My problem is that I would like to have a way to signal (when returning value from getListForThisRegion) "value not found" to the caller. If I was returning a pointer, I could return nullptr, but I don't know how to do it with references. All I can think of is having some static member not_found of type MyList, and returning a reference to it, but it seems ugly.

And yes, I can't return value because lists are "fat" and often used.

EDIT: ton of great answers , but exception is not an acceptable solution because the number of times it would be raised is high (the percentage nbNotFound/nbCalls is high).
EDIT2: regarding boost::optional - how complicated it is to master? I mean does it require some non obvious knowledge (non obvious= something that is not simply knowing the syntax)?

NoSenseEtAl
  • 28,205
  • 28
  • 128
  • 277
  • 3
    throwing an exception can be a good option. – BigMike Oct 21 '11 at 09:18
  • 1
    you might also want to look at `boost::optional` – Akanksh Oct 21 '11 at 09:23
  • A reference has to refer to an object, so you either throw an exception or don't use a reference. `boost::optional` is a great choice, but that may be overkill; just use a pointer. – GManNickG Oct 21 '11 at 09:25
  • You can do same thing as I suggested here (basic idea): [notify the caller of not found element](http://stackoverflow.com/questions/7376985/invalid-initialization-of-non-const-reference-when-returning-an-array-element) – Nawaz Oct 21 '11 at 09:31

5 Answers5

8

There are two idiomatic ways to handle this:

  • Change your interface to return a type that has the ability to refer to nothing (e.g. a pointer that can be null, an iterator to end).

Or

  • Throw an exception if the item isn't found.

Returning a dummy object is a bit hacky, and you don't gain anything over returning a pointer as you still have to check the result against a special value (null or the dummy object).

JoeG
  • 12,994
  • 1
  • 38
  • 63
  • @edA-qamort-ora-y: that would change the semantics to return by value rather than reference (unless you return an optional reference, but I don't see what that adds to a pointer). – Mike Seymour Oct 21 '11 at 10:12
  • @Mike: How about `boost::optional >`? – fredoverflow Oct 21 '11 at 10:17
  • @MikeSeymour, agreed. It depends on the type what is best. For larger object types I tend to use a pointer, and for small/fundamentals an optional. – edA-qa mort-ora-y Oct 21 '11 at 10:18
  • 1
    @FredOverflow: You could, but `MyList const *` gives the same semantics, lower runtime cost, const-correctness, and less verbosity, so I'd prefer that. – Mike Seymour Oct 21 '11 at 10:19
  • @FredOverflow: When used as a return type, I don't see that `boost::optional >` provides any benefit over `MyList*`. – JoeG Oct 21 '11 at 10:36
  • @Joe: returning an optional reference instead of a pointer prevents the user of the function from wondering wheter he must release the memory himself or not. – Luc Touraille Oct 21 '11 at 12:10
  • @Luc: There's no need to wonder about that. If it returns an unmanaged pointer then either the caller is not responsible for it, or it needs to be rewritten to return a smart pointer. – Mike Seymour Oct 21 '11 at 13:20
  • @Mike: I guess you're right, smart pointers can indeed be used to make the ownership policy explicit, making return by pointer the best solution here. – Luc Touraille Oct 21 '11 at 15:00
3

How about rewriting the function to take reference to "returnValue" where you put the list to return? Then the function can return boolean value indicating found/ not found.

bool getListForThisRegion(/*region ID, ...*/, MyList& ret_list);
Jonny
  • 31
  • 1
1

I'd write exception class (hierarchy, if needed) and throw an exception for such case.

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
1

I only see two possibilities: either you have a special member in the MyList class declaring that an instance is "null" (not set) or you could throw an exception.

Markus Pilman
  • 3,104
  • 3
  • 22
  • 31
  • 1
    Having a member in `MyList` to indicate the null value seems very intrusive. This kind of feature is often better achieved by wrapping the object into another one. `Boost.Optional` provides such a wrapper for representing a nullable object. – Luc Touraille Oct 21 '11 at 09:49
1

You could follow std::map's lead, and insert a default constructed list into your container, and return a reference to that. Obviously, this depends on there not being a semantic difference between a default list, and a list that isn't there at all.

You can also add a query function that searches for a particular region, and returns true if it has a list, and false otherwise. Then, you can throw an exception in your accessor safe in the knowledge that it will not be a common occurrence.

Dennis Zickefoose
  • 10,791
  • 3
  • 29
  • 38