dimanche 19 mars 2023

std::erase does not return an error when std::remove_if is used inappropriately in the erase-remove idiom

As we know, the erase-remove idiom can be used as a concise pattern to delete elements of a vector.

In particular, std::remove_if swaps elements inside the vector in order to put all elements that do not match the predicate towards the beginning of the container. These elements are then removed from the container.

This also means that if the predicate (body of the lambda function) returns true, then that element will be placed at the end of the vector.

It must be noted that within the erase remove idiom, both the erase and remove functions must get iterators to the same container. This means that if I try to provide a different iterator in the remove_if statement, the erase function must return an error.

But consider the code below:

vector<int> valsToRemove{ 4, 5, 6, 2, 3, 7, 10 };
    
vector<int> isValidToRemove{ 0, 1, 0, 1, 1, 0, 1 };
    
valsToRemove.erase(std::remove_if(isValidToRemove.begin(),
                                isValidToRemove.end(),
                                [&](int& x)-> bool { return x == 0; }), valsToRemove.end() );
                                
for( auto& val: valsToRemove ) {
        cout << val << "\t";
}

It turns out that I have a vector isValidToRemove which tells me whether an element of the valsToRemove vector must be retained or deleted based on "0" or "1" value. I use this within the remove_if statement to satisfy a predicate. In this case, due to different containers being used in the erase and remove_if functions, the erase function must return an error.

However, I get an arbitrary output which somehow appends additional elements of the vector. The output also varies across different instances/machines.

4 5 6 2 3 7 10 0 0 0 49 0 1 1 1 1

I just wanted to confirm if this should be the correct behavior or if it should be modified so that the correct error is returned to the user/client of this function.

Further, is there a concise way or a specific pattern to use a separate vector (such as isValidToRemove in the example above which might be received from an upstream component) to remove elements of a different vector (valsToRemove in the example above) instead of just using a for loop to remove these elements.

Aucun commentaire:

Enregistrer un commentaire