Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 689
j00hi Avatar asked May 11 '19 14:05

j00hi


People also ask

What you have to do to actually remove the specified elements from the container?

First, you use remove_if/remove to move all elements which don't fit the remove criteria to the front of the range, keeping the relative order of the elements. So after calling remove_if/remove , a single call of erase deletes all remaining elements at the end of the range.


Video Answer


1 Answers

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());
like image 52
Pete Becker Avatar answered Nov 13 '22 00:11

Pete Becker