Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle std::find_if() returning false?

Take the following example taken from the cplusplus.com reference page and altered to return false:

// find_if example
#include <iostream>     // std::cout
#include <algorithm>    // std::find_if
#include <vector>       // std::vector

bool IsOdd (int i) {
  return ((i%2)==1);
}

int main ()
{
  std::vector<int> myvector;    
  myvector.push_back(10);
  myvector.push_back(20);
  myvector.push_back(40);
  myvector.push_back(50);

  std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
  std::cout << "The first odd value is " << *it << '\n';

  return 0;
} 

Since no value in myvector is odd it will return InputIterator last, which is undefined:

The first odd value is -1727673935

What is the proper way to handle this output?

How can I know std::find_if() returned false if the output is unpredictable and comparing to the entire vector to confirm the resulting value doesn't exist defeats the purpose of using std::find_if() to begin with?

like image 888
A__ Avatar asked May 06 '19 16:05

A__


3 Answers

Do you mean

std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);

if ( it != myvector.end() )
{
    std::cout << "The first odd value is " << *it << '\n';
}
else
{
    // std::cout << "there is no odd value in the vector\n";
}
like image 86
Vlad from Moscow Avatar answered Oct 05 '22 23:10

Vlad from Moscow


The idiomatic way to do this is to check whether the iterator equals the end sentinel.

auto it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
if (it == myvector.end()) {
    std::cout << "No odd values found" << std::endl;
} else {
    std::cout << "The first odd value is " << *it << std::endl;
}

In C++17 (the most recent standard), you can declare the iterator right in the if statement:

if (auto it = std::find_if(myvector.begin(), myvector.end(), IsOdd); it != myvector.end()) {
    std::cout << "The first odd value is " << *it << std::endl;
} else {
    std::cout << "No odd values found" << std::endl;
}
like image 21
Brennan Vincent Avatar answered Oct 06 '22 00:10

Brennan Vincent


You need to check if the returned iterator is the end iterator you passed to std::find_if (the second argument). These semantics are quite common for algorithms in the standard library, so you should get used to this.

const auto firstOdd = std::find_if (myvector.cbegin(), myvector.cend(), IsOdd);

if (firstOdd != myvector.cend())
    std::cout << "The first odd value is " << *it << '\n';
else
    std::cout << "No odd values found\n";

Note also that you can use the cbegin()/cend() member functions, as you're not mutating the container.

like image 43
lubgr Avatar answered Oct 06 '22 01:10

lubgr