Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is std::remove_if guaranteed to call predicate in order?

Will std::remove_if always call the predicate on each element in order (according to the iterator's order) or could it be called out of order?

Here is a toy example of what I would like to do:

void processVector(std::vector<int> values)
{
    values.erase(std::remove_if(values.begin(), values.end(), [](int v)
    {
        if (v % 2 == 0)
        {
            std::cout << v << "\n";
            return true;
        }
        return false;
    }));
}

I need to process and remove all elements of a vector that meet certain criteria, and erase + remove_if seems perfect for that. However, the processing I will do has side effects, and I need to make sure that processing happens in order (in the toy example, suppose that I want to print the values in the order they appear in the original vector).

Is it safe to assume that my predicate will be called on each item in order?

I assume that C++17's execution policies would disambiguate this, but since C++17 isn't out yet that obviously doesn't help me.

Edit: Also, is this a good idea? Or is there a better way to accomplish this?

like image 987
Solaraeus Avatar asked Aug 08 '16 22:08

Solaraeus


People also ask

How does std:: remove_ if work?

std::remove, std::remove_if. Removes all elements satisfying specific criteria from the range [first, last) and returns a past-the-end iterator for the new end of the range. 1) Removes all elements that are equal to value , using operator== to compare them. 3) Removes all elements for which predicate p returns true.

How does remove if work C++?

C++ Algorithm remove_if() function is used to eliminate all the elements that satisfy a predicate from a given range [first, last) without disturbing the order of the remaining elements. This function cannot alter the size of the container. It returns an iterator to the new end of the range.

What STD remove returns?

std :: remove It removes value from range. Transforms the range [first,last) into a range with all the elements that compare equal to val removed, and returns an iterator to the new end of that range.

How do you get rid of an STD?

Antibiotics, often in a single dose, can cure many sexually transmitted bacterial and parasitic infections, including gonorrhea, syphilis, chlamydia and trichomoniasis. Typically, you'll be treated for gonorrhea and chlamydia at the same time because the two infections often appear together.


1 Answers

The standard makes no guarantees on the order of calling the predicate.

What you ought to use is stable_partition. You partition the sequence based on your predicate. Then you can walk the partitioned sequence to perform whatever "side effect" you wanted to do, since stable_partition ensures the relative order of both sets of data. Then you can erase the elements from the vector.

stable_partition has to be used here because erase_if leaves the contents of the "erased" elements undefined.

In code:

void processVector(std::vector<int> &values)
{
    auto it = std::stable_partition(begin(values), end(values), [](int v) {return v % 2 != 0;});

    std::for_each(it, end(values), [](int v) {std::cout << v << "\n";});

    values.erase(it, end(values));
}
like image 76
Nicol Bolas Avatar answered Sep 20 '22 09:09

Nicol Bolas