Why do I get a different result if instead of x I directly pass array element ar[0] in std::remove function?

Viewed 58
#include <iostream>
#include <vector>
#include <set>
#include <algorithm>

using namespace std;

int main()
{
    vector<int> ar = {1, 2, 2, 2, 3, 4, 5, 5, 5, 6, 7};
    vector<int> sum;
    int n = ar.size();
    for (int i = 0; i < n; i++)
    {
        int x = ar[0];
        int frq = count(ar.begin(), ar.end(), x);
        int q = frq / 2;
        sum.push_back(q);

        ar.erase(remove(ar.begin(), ar.end(), x), ar.end()); // Doubt
    }
    int count = 0;
    int n1 = sum.size();
    for (int i = 0; i < n1; i++)
    {
        count = count + sum[i];
    }
    cout << count;
}

Why do I get a different result if instead of x I directly pass ar[0] in the std::remove function?

x and ar[0] have the same value.

1 Answers

The reason is that std::remove takes the last parameter by reference. From cppreference:

Because std::remove takes value by reference, it can have unexpected behavior if it is a reference to an element of the range [first, last).

It is a bit tricky, because the paramter is passed as const reference:

template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );

However, just because ar[0] is passed as const reference does not imply that ar[0] cannot be modified by other means. In this case it is modified through first / last. Actually I cannot think of a case where it would be "ok" to have an element inside [first, last) as value.

For illustration, consider that you get the same wrong output with ar[0] as if you declared x as a reference:

int& x=ar[0];
ar.erase(remove(ar.begin(),ar.end(),x),ar.end());

Here x is passed as const reference, but the algorithm does modify ar[0].

Related