2

I have a small problem with lambda expression while using remove_if on std::vector

I have a following piece of code :

    std::remove_if( openList.begin(), openList.end(), 
        [&](BoardNode& i){
            std::cout<< i.getCoordinates() << std::endl;
            std::cout<< currentNode.getCoordinates() << std::endl;
            return i.getCoordinates() == currentNode.getCoordinates(); }
        );

There is no compiler error with this, but the elements which return true from the above statement won't be removed from the vector;

I get printed on the screen e.g.

[5,5]
[5,5]

but the openList remains as it was.

B. Decoster
  • 7,723
  • 1
  • 32
  • 52
Patryk
  • 22,602
  • 44
  • 128
  • 244
  • 3
    Are you sure the error is from the first code sample? – juanchopanza Nov 23 '12 at 16:35
  • 2
    What do you mean by "during debugging I don't get i's coordinates"? As far as I can see, the first example is correct, and the second example is wrong because the predicate takes an iterator rather than `BoardNode`. – Mike Seymour Nov 23 '12 at 16:39
  • 1
    Also, what does the title mean by "does not want to return a proper type"? Your lambda correctly returns `bool`. – Mike Seymour Nov 23 '12 at 16:43
  • Well, the second version is plain wrong, so no point in figuring out why it "doesn't work". As for the first version, it looks syntactically OK. – juanchopanza Nov 23 '12 at 16:44
  • 1
    @juanchopanza: He needs to capture `currentNode`. – Benjamin Lindley Nov 23 '12 at 16:45
  • 2
    Is the problem that the element's aren't actually removed from the vector? You need the erase-remove idiom for that: `openList.erase(std::remove_if(...), openList.end()); – Mike Seymour Nov 23 '12 at 16:46
  • @BenjaminLindley You are completely right, thanks! – juanchopanza Nov 23 '12 at 16:46
  • @MikeSeymour Can you post an answer so that I can check it out ? – Patryk Nov 23 '12 at 16:47
  • Edits completely changed the nature of this question. I've been trying to debug this for the last 10 minutes just to figure out what the question *really* was. Oh well. – John Dibling Nov 23 '12 at 16:49

3 Answers3

10

std::remove_if doesn't erase anything from the vector, since it doesn't have access to it. Instead, it moves the elements you want to keep to the start of the range, leaving the remaining elements in a valid but unspecified state, and returns the new end.

You can use the "erase-remove" idiom to actually erase them from the vector:

openList.erase(
    std::remove_if( 
        openList.begin(), 
        openList.end(), 
        [&](BoardNode& i){return i.getCoordinates() == currentNode.getCoordinates();}),
    openList.end());
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • Excuse me i'm really having trouble understanding what goes in the square brackets of a lambda would you be able to explain that to me? – Holly Dec 04 '12 at 21:37
3

I think you intend to remove items from the vector. But what you do, would not really remove the items from the vector, which makes you think that the lambda doesn't work. You need to use erase() member function in conjunction with std::remove.

In other words, you have to use erase-remove idiom as:

v.erase(std::remove_if(v.begin(), v.end(), your-lambda-goes-here), v.end());
Nawaz
  • 353,942
  • 115
  • 666
  • 851
0

Removing is done by shifting the elements in the range in such a way that elements to be erased are overwritten. The elements between the old and the new ends of the range have unspecified values. An iterator to the new end of the range is returned. Relative order of the elements that remain is preserved.

http://en.cppreference.com/w/cpp/algorithm/remove

Also, check the example on that link.

hate-engine
  • 2,300
  • 18
  • 26