Search code examples
c++stlerase-remove-idiom

For the erase-remove idiom, why is the second parameter necessary which points to the end of the container?


Consider the following code (taken from cppreference.com, slightly adapted):

#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>

int main()
{
    std::string str1 = "     Text with some   spaces";
    str1.erase(std::remove(str1.begin(), str1.end(), ' '), str1.end());
    std::cout << str1 << '\n';

    return 0;
}

Why is the second parameter to erase neccessary? (I.e. str1.end() in this case.)

Why can't I just supply the iterators which are returned by remove to erase? Why do I have to tell it also about the last element of the container from which to erase?

The pitfall here is that you can also call erase without the second parameter but that produces the wrong result, obviously.

Are there use cases where I would not want to pass the end of the container as a second parameter to erase?

Is omitting the second parameter of erase for the erase-remove idiom always an error or could that be a valid thing to do?


Solution

  • std::remove returns one iterator; it's the new past-the-end iterator for the sequence. But when the sequence is managed by a container, the size of the container hasn't changed; std::remove shuffles the order of the elements in the sequence, but doesn't actually remove any of them.

    To get rid of the elements in the container that are not part of the new sequence you call, of course, container.erase(). But the goal is to remove all the extra elements; calling container.erase() with only one iterator tells it to remove that element. To tell container.erase() to erase everything "from here to the end" you have to tell it both where "here" is and where the end is. So that means two iterators.

    If it helps, think of the "remove/erase" idiom as two separate steps:

    auto new_end = std::remove(str1.begin(), str1.end(), ' ');
    str1.erase(new_end, str1.end());