c++iteratorstd-algorithm

Inconsistent output with std::any_of


I have two version of the same function using std::any_of and std::find_if for checking whether an int exist in a vector (returned from g.getEdges()).

However when I repeatedly run the std::any_of the return value is inconsistent, while std::find_if is.

Both versions are as follow (g.getEdges() returns an int vector, while this->s is an int):

bool Search::marked(const int &v) {
    return std::any_of(begin(g.getEdges(v)), end(g.getEdges(v)), [this](const int &w) { return w == this->s; });
}
bool Search::marked(const int &v) {
    auto it = std::find_if(begin(g.getEdges(v)), end(g.getEdges(v)), [this](const auto &w) { return w == this->s; });
    return it != end(g.getEdges(v));
}

In both classes, adj is the vector being iterated:

class Graph {
  public:
    Graph() : vertex(0), edges(0) {
      adj = std::make_unique<std::vector<std::vector<int>>>(0);
    }
    const std::vector<int> getEdges(int v) { return (*adj)[v]; }
  // ... rest of public
  private:
    std::shared_ptr<std::vector<std::vector<int>>> adj; // Shared for Search class
}

class Search {
  public:
    Search(Graph &g_, int s_) : g(g_), s(s_) {}
    int count();
    bool marked(const int &v);

  private:
    Graph &g;
    int s;
};

The gtest function I used to check the code:

TEST(searchClassTest, HandlesPositiveInput) {
    // ... init myGraph ...
    Search mySearch(myGraph, 2);  // 2 is s!
    EXPECT_EQ(mySearch.count(), 2);
    EXPECT_EQ(mySearch.marked(1), true);
    EXPECT_EQ(mySearch.marked(3), true);
}

Why am I getting inconsistent results?

Link to minimal reproducible example: https://godbolt.org/z/9TnGq3Wbs


Solution

  • The code you presented is totally invalid due to

    const std::vector<int> getEdges(int v)
    

    In both implementation of marked, you call this function multiple times, each time getting a different copy of a vector, then try to compare their iterators:

    bool Search::marked(const int &v) {
        // begin and end point to two different vectors
        auto it = std::find_if(begin(g.getEdges(v)), end(g.getEdges(v)), [this](const auto &w) { return w == this->s; });
        // this end points to a third one
        return it != end(g.getEdges(v)) ? true : false;
    } 
    

    The std::any_of version is broken in the same way. Trying to iterate from one vector to another is Undefined Behavior, so any results you see might as well be random - function might return true, false, 7 or "nasal demons, here I come".

    Simply changing getEdges to return a reference should fix this.