10

I have a struct Foo. In pseudocode:

def FindFoo:
   foo = results of search
   foundFoo = true if a valid foo has been found  

   return foo if foundFoo else someErrorCode

How can I accomplish this in C++?

Edited to remove numerous inaccuracies.

Doro
  • 755
  • 8
  • 25
Nick Heiner
  • 119,074
  • 188
  • 476
  • 699
  • 1
    Your return type is inconsistent. If the search succeeds, it is `Foo&`; if it fails, it is `ErrorCode`. A solution to this problem would be to return a `Foo*`, which points to the element that was found, or is NULL if no element was found. – isekaijin Jun 16 '10 at 15:13
  • Related, maybe duplicate: [Nullable values in C++](https://stackoverflow.com/q/2537942) – jrh May 11 '20 at 21:33

8 Answers8

15

C++ objects can never be null or empty. Pointers can hold a null pointer value indicating they point at nothing.

The typical solution would be to throw an exception. Otherwise, use a pointer; just make sure you aren't returning the address of a temporary.

I wouldn't recommend trying to teach yourself C++ with knowledge from other languages, you'll hurt yourself. Grab a good beginner-level book, it's the best way to learn.

Community
  • 1
  • 1
GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • 1
    I think the typical solution would be to mimik the STL which returns an iterator like object that point to invalid objects (one past the end of the container). – Martin York Jun 16 '10 at 00:25
  • @Martin: I'll just say that's a more generalized pointer and meet you half-way. :P – GManNickG Jun 16 '10 at 05:35
  • Returning an iterator-like object only makes sense if you're creating a container that you want to be able to iterate over. Where a `find` function is involved, that's potentially the case, but not necessarily. – Tyler McHenry Jun 16 '10 at 15:04
  • 1
    I think doing C++ by applying knowledge from other languages is excellent; it will improve C++ to become more modern in the end. – Jonny Aug 07 '15 at 06:56
3

Throw an exception. That's what they're for.

Puppy
  • 144,682
  • 38
  • 256
  • 465
3

You can look into boost::optional and see if it fits your needs. However:

return foo if foundFoo else someErrorCode

This makes me think that you might be better off throwing an exception if you don't find foo.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
2

One way of doing it is to return a pointer to a foo:

public Foo* findFoo()
{
    return fooFound ? new fooResult() : NULL;
}

Another possibility to define a NullFoo of some kind, possibly as a struct extending Foo with an empty implementation. For more information about the latter idea, you can read about the Null Object Pattern.

Edit: The modified question is somewhat different, and as other people have mentioned, you may be best off throwing an exception rather than doing either of the above.

Justin Ardini
  • 9,768
  • 2
  • 39
  • 46
0

That doesn't work in C# either. You should return a pointer to Foo.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
0

It's not possible in C++ without resorting to pointers or a library solution outside the standard library. (Boost is not a part of the standard library, it's a 3rd party solution.)

In C#, you can use a Nullable<Foo>.

Contrary to Billy's comment, structs are value types, not reference types, and Nullable can be applied to any value type, not just built-ins. The following compiles just fine:

struct Test {
    int Blah;
}
void Main() {
    System.Nullable<Test> proof;
}
zildjohn01
  • 11,339
  • 6
  • 52
  • 58
  • No, you can't. First of all, Nullable is only valid on the internal types, not on user defined types like `Foo`. Second, even if it were valid, it'd not help you anyway because object references can already be null. And finally, the OP asked to return an error code, not NULL. – Billy ONeal Jun 15 '10 at 23:46
  • @Billy: Easy on the -1s. struct means value type, not reference and you can do a nullable value type - that's the whole point – Ruben Bartelink Jun 15 '10 at 23:48
  • 1
    +1 factually correct re the .NET bit. Ditto the C++ bit, though omits ways around dropping to pointers [such as Null Object pattern, throwing, wrapping in a boost::optional]. +1ing as answer not off topic or incorrect. Far more irellevant and incomplete answers have been upvoted here. – Ruben Bartelink Jun 16 '10 at 00:03
0

Is not finding a foo really an exceptional situation? Then throw an exception. Expect to not find foo? have the function return an error code and pass the foo out via a reference parameter, where foo is only valid if the function returns no error.

stonemetal
  • 6,111
  • 23
  • 25
-1

You cant do this in C# either - you would need to return new Foo(), not null to make the compiler happy.

Ditto the C++ case - you need to instantiate a struct if you're going to return by value. If not, you want to return by pointer (in which case you'd be newing or returning a pointer to one allocated in another manner, which brings messy ownership transfer semantics into the equation).

EDIT: Based on your update. It seems you want to return either a value or a 'null' meta-value that indicates 'not found'. You can do this in a number of ways:

  1. throw if it fails, otherwise unconditionally return a value
  2. return a pointer - but this leaves the responsibility for deleting it up in the air if it's not something that's going to stay in memory long term
  3. wrap it in a [templated] wrapper object that handles the conditionality in the same way that .NET's Nullable<T> would (I'll let someone chime in with the right one UPDATE: @Mike Seymour says it's boost::optional<foo>)
  4. use the Null Object pattern to return an appropriate value which does the right thing when treated as a valid resut on the client side
Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249