1

I've made some minimal code

vector<int> items = {1, 2, 5, 0, 7};
int& getAtSafe(unsigned n) {
    if (n < items.size() && items[n] != 5) return items[n];
    else // ???
}

But how to return something as null when we can't find needed item?
P.S. Original task is searching item with property equal to.

Exception variants not accepted. I do not need to pause the program.
As an example, user types index, and each time when it's wrong, the user gets "Bad input"

7
  • 10
    There are no null references in C++, this is not Java. Why you don't use std::vector::at(), which does exactly what you're trying to do? Commented Nov 19, 2019 at 8:31
  • References always must refer to some valid address. If you try to get to something else (via dirty hacks), you're in the land of undefined behaviour! Commented Nov 19, 2019 at 8:34
  • 4
    exceptions != "pause the program". Signaling "Bad input" to a user is a valid use case for an exception (of course the calling code would have to catch it) Commented Nov 19, 2019 at 8:36
  • 3
    there is no problem with it. Perhaps you misunderstand how exceptions work, that would be worth a different question Commented Nov 19, 2019 at 8:39
  • 1
    Exceptions are perhaps more interesting than might appear to you, you could have multiple access to your vector and just place one single, large try-catch around. Error handling you'd then need only once. Sure, not always appropriate, but if, pretty convenient... Commented Nov 19, 2019 at 8:58

4 Answers 4

7

If the function checks the index then a general approach in such a case is to throw an exception std::out_of_range.

Take into account that there is already the member function at in the class template std::vector.

If you may not use exceptions and the task is

P.S. Original task is searching item with property equal to.

then you can use either the standard algorithm std::find_if that returns an iterator or you can write your own function that returns the index that corresponds to the searched element. If there is no such an element then return the size of the vector, For example

#include <iostream>
#include <vector>

template <typename Predicate>
std::vector<int>::size_type find_if( const std::vector<int> &v, Predicate predicate )
{
    std::vector<int>::size_type i = 0;

    while ( i != v.size() && !predicate( v[i] ) ) ++i;

    return i;
}

int main() 
{
    std::vector<int> items = {1, 2, 5, 0, 7};

    auto i = ::find_if( items, []( const auto &item ) { return item % 2 == 0; } );

    if ( i != items.size() ) std::cout << items[i] << '\n';

    return 0;
}
Sign up to request clarification or add additional context in comments.

5 Comments

I suggest adding a link to the cppreference page on std::vector::at to the answer (en.cppreference.com/w/cpp/container/vector/at)
@JavascriptDev That was added after the answer was posted...
@JavascriptDev Not accepted at all? Why? Or, not accepted to be propagated out of the program? Then, you can simply catch them out of getAtSafe (or, better items.at(n)) and print an error message.
@JavascriptDev His task is different. In fact he needs to use the standard algorithm std::find_if.
Originally, I've been making a recursive find.
4

C++ has value semantics. There are nullptrs but there is no null value. A reference always references something. Ergo, there cannot be a reference to null.

Several options you have:

  • throw an exception. Your argument for rejecting them is moot. std::vector::at does exactly that (but I suppose your code is just an example for a more general situation)
  • return a pointer that can be nullptr (not recommended, because then you put the resonsibility on handling it correctly on the caller)
  • return a std::optional. Again this forces the caller to handle the case of "no value returned" but in contrast to returning a nullptr the caller gets a well-designed interface that is hard to use wrong.
  • return an iterator. end is often used to signal "element not found" throughout the standard library, so there will be little surprise if you do the same.
  • perhaps this is not just an example for a different situation, then you should use std::vector::at instead of your handwritten function and be done with it.

P.S. Original task is searching item with property equal to.

You should use std::find to find an item in a container. It returns end of the container when the element cannot be found.

Comments

2

Without changing the prototype, you are restricted to throw an exception.

If changing the prototype is an option, you can:

  • return a pointer (and use nullptr as sentinel)
  • return an iterator (and use items.end() as sentinel)
  • return an std::optional<std::reference_wrapper<int>> (and use the absence of value as sentinel, you need then C++17 or boost).

Comments

0

One of the use cases of references in C++ is to be sure that you don't have a null pointer. So by definition, it is impossible to return null as a reference.

However, different strategies can be considered:

  • Return iterators: use std::end(items) as the null value
  • Return by value
  • Throw an exception if no element is valid

2 Comments

Returning by value does not solve this particular problem.
imho this isnt quite clear. One can return a reference to a null pointer. I admit this is a weird interpretation of what you are writing, but still it can be misunderstood

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.