How these lines execute [duplicate] - c++

int main()
{
const int SIZE = 10;
int a[SIZE] = {10, 2, 35, 5, 10, 26, 67, 2, 5, 10};
std::ostream_iterator< int > output(cout, " ");
std::vector< int > v(a, a + SIZE);
std::vector< int >::iterator newLastElement;
cout << "contents of the vector: ";
std::copy(v.begin(), v.end(), output);
newLastElement = std::remove(v.begin(), v.end(), 10);
cout << "\ncontents of the vector after remove: ";
//std::copy(v.begin(), newLastElement, output);
//this gives the correct result : 2 35 5 26 67 2 5
std::copy(v.begin(), v.end(), output);
//this gives a 10 which was supposed to be removed : 2 35 5 26 67 2 5 2 5 10
cout << endl;
return 0;
}
There are three 10 in the array a.
why does the array v contains a 10 after we remove the all the 10s with remove function.
you can see the compiled output also here

Actually std::remove doesn't remove the item from the container. Quoted from here
Remove removes from the range [first, last) all elements that are equal to value. That is, remove returns an iterator new_last such that the range [first, new_last) contains no elements equal to value. The iterators in the range [new_last, last) are all still dereferenceable, but the elements that they point to are unspecified. Remove is stable, meaning that the relative order of elements that are not equal to value is unchanged.`
That is, std::remove works with a pair of iterators only and does not know anything about the container which actually contains the items. In fact, it's not possible for std::remove to know the underlying container, because there is no way it can go from a pair of iterators to discover about the container to which the iterators belong. So std::remove doesn't really remove the items, simply because it cannot. The only way to actually remove an item from a container is to invoke a member function on that container.
So if you want to remove the items, then use Erase-Remove Idiom:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
The erase-remove idiom is so common and useful is that std::list has added another member function called list::remove which produces the same effect as that of the erase-remove idiom.
std::list<int> l;
//...
l.remove(10); //it "actually" removes all elements with value 10!
That means, you don't need to use erase-remove idiom when you work with std::list. You can directly call its member function list::remove.

The reason is that STL algorithms do not modify the size of the sequence. remove, instead of actually erasing items, moves them and returns an iterator to the "new" end. That iterator can then be passed to the erase member function of your container to actually perform the removal:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
By the way, this is known as the "erase-remove idiom".
EDIT: I was incorrect. See comments, and Nawaz's answer.

Because std::remove doesn't actually shrink the container, it just moves all the elements down to to fill up the spot used by the "removed" element. For example, if you have a sequence 1 2 3 4 5 and use std::remove to remove the value 2, your sequence will look like 1 3 4 5 5. If you then remove the value 4, you'll get 1 3 5 5 5. At no point does the sequence ever get told to be shorter.

C++20 introduces a new non-member function std::erase that simplifies this task for all standard library containers.
The solution suggested by multiple older answers here:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
Can now be written as:
std::erase(v, 10);

Related

How to erase reverse_iterator correctly when erase and push_back happens?

I have a list container, which looks like:
std::list<int> l = {1,2,3,4,5,6,7,8};
i often erase elements, so i choose std::list.
but, i also want to find the elemnt in O(1), so i record the reverse_iterator.
For Example:
l.push_back(9);
auto s = l.rbegin(); // record the iterator of 9, in order to erase it in the future fastly.
cout << *s << endl;
l.push_back(10);
auto s2 = l.rbegin();
but when i erase like this:
l.erase(std::next(s).base()); // s the iterator of 9, in my brain
i want to erase 9, but actually, it erase 10.
I have two questions:
why i should use next? actually my *s can get the element, which is different with .end().
how can i make the erase happen in my previous saved iterator?
Since the iterator of the list is a bidirectional iterator, instead of using reverse_iterator, you can just use --l.end() to get the last valued iterator.
std::list<int> l = {1,2,3,4,5,6,7,8};
l.push_back(9);
auto s = --l.end(); // record the iterator of 9
l.push_back(10);
l.erase(s); // erase the iterator of 9
Demo.
l.rbegin().base() == l.end(), which is not the position of the last element, but the end of the list. and push_back again won't affect this existing iterator, it is still pointing to the end of the list.
Then std::next(l.rbegin()).base() == l.end() - 1, which now is pointing to the last element 10.
So if you want to remember the position of the 9, you better use a normal iterator instead of a reverse one, or, use a reverse iteractor whose base pointing to 9, and that should be auto s = std::next(l.rbegin()), and erase it as l.erase(s.base()).
the rule is &*r == &*(i-1)

remove algorithm unexpected behaviour [duplicate]

I am bit confused about the difference between the usage of std::remove algorithm. Specifically I am not able to understand what is being removed when I use this algorithm. I wrote a small test code like this:
std::vector<int> a;
a.push_back(1);
a.push_back(2);
std::remove(a.begin(), a.end(), 1);
int s = a.size();
std::vector<int>::iterator iter = a.begin();
std::vector<int>::iterator endIter = a.end();
std::cout<<"Using iter...\n";
for(; iter != endIter; ++iter)
{
std::cout<<*iter<<"\n";
}
std::cout<<"Using size...\n";
for(int i = 0; i < a.size(); ++i)
{
std::cout<<a[i]<<"\n";
}
The output was 2,2 in both the cases.
However, if I use erase with the remove something like this:
a.erase(std::remove(a.begin(), a.end(), 1), a.end());
I get the output as 2.
So my questions are:
(1). Is there any use of std::remove other than using it with erase function.
(2). Even after doing std::remove, why a.size() returns 2 and not 1?
I read the item in Scott Meyer's Effective STL book about the erase-remove idiom. But am still having this confusion.
remove() doesn't actually delete elements from the container -- it only shunts non-deleted elements forwards on top of deleted elements. The key is to realise that remove() is designed to work on not just a container but on any arbitrary forward iterator pair: that means it can't actually delete the elements, because an arbitrary iterator pair doesn't necessarily have the ability to delete elements.
For example, pointers to the beginning and end of a regular C array are forward iterators and as such can be used with remove():
int foo[100];
...
remove(foo, foo + 100, 42); // Remove all elements equal to 42
Here it's obvious that remove() cannot resize the array!
What does std::remove do?
Here's pseudo code of std::remove. Take few seconds to see what it's doing and then read the explanation.
Iter remove(Iter start, Iter end, T val) {
Iter destination = start;
//loop through entire list
while(start != end) {
//skip element(s) to be removed
if (*start == val) {
start++;
}
else //retain rest of the elements
*destination++ = *start++;
}
//return the new end of the list
return destination;
}
Notice that remove simply moved up the elements in the sequence, overwriting the values that you wanted to remove. So the values you wanted to remove are indeed gone, but then what's the problem? Let say you had vector with values {1, 2, 3, 4, 5}. After you call remove for val = 3, the vector now has {1, 2, 4, 5, 5}. That is, 4 and 5 got moved up so that 3 is gone from the vector but the size of vector hasn't changed. Also, the end of the vector now contains additional left over copy of 5.
What does vector::erase do?
std::erase takes start and end of the range you want to get rid off. It does not take the value you want to remove, only start and end of the range. Here's pseudo code for how it works:
erase(Iter first, Iter last)
{
//copy remaining elements from last
while (last != end())
*first++ = *last++;
//truncate vector
resize(first - begin());
}
So the erase operation actually changes the size of container and frees up the memory.
The remove-erase idiom
The combination of std::remove and std::erase allows you to remove matching elements from the container so that container would actually get truncated if elements were removed. Here's how to do it:
//first do the remove
auto removed = std::remove(vec.begin(), vec.end(), val);
//now truncate the vector
vec.erase(removed, vec.end());
This is known as the remove-erase idiom. Why is it designed like this? The insight is that the operation of finding elements is more generic and independent of underlying container (only dependent on iterators). However operation of erase depends on how container is storing memory (for example, you might have linked list instead of dynamic array). So STL expects containers to do its own erase while providing generic "remove" operation so all containers don't have to implement that code. In my view, the name is very misleading and std::remove should have been called std::find_move.
Note: Above code is strictly pseudocode. The actual STL implementation is more smarter, for example, using std::move instead of copy.
std::remove does not remove the actual objects, rather, pushes them to the end of the container. Actual deletion and deallocation of memory is done via erase. So:
(1). Is there any use of std::remove other than using it with erase function.
Yes, it helps to get a pair of iterators to a new sequence without having worry about proper de-allocation etc.
(2). Even after doing std::remove, why a.size() returns 2 and not 1?
The container still holds to those objects, you only have a new set of iterators to work with. Hence the size is still what it used to be.
i faced the same issue, trying to understand the difference.
the explanations that have been give so far are right on the money, but i only understood them after seeing an example;
#include <algorithm>
#include <string>
#include <iostream>
#include <cctype>
int main()
{
std::string str1 = "Text with some spaces";
std::string::iterator it = remove(str1.begin(), str1.end(), 't');
std::cout << str1 << std::endl;// prints "Tex wih some spaceses"
for (str1.begin();it != str1.end(); ++it)
{
std::cout << *it; //prints "es"
}
}
as you can see, the remove, only moves the lower case 't' to the end of the string, while returning a new iterator to the end of the new string (new string is the old string up to where the removed element are inserted)
this is why when you print the iterator that you got from "remove"
"Text with some spaces"
^ ^removes both 't', then shift all elements forward -1 //what we want to remove
"Text with some spaces"
^ end of string -2 //original state of string
"Tex with some spacess"
^end of string -3 //first 't' removed
"Tex wih some spaceses"
^end of string -4 //second 't' removed
"Tex wih some spaceses"
^new iterator that remove() returned -5 // the state of string after "remove" and without "erase"
if you pass the iterator you obtained from step 5 to "erase()" it will know to erase from there to the end of string re-sizing the string in process
To remove element with some condition(equal some value or other condition like less than) in container like vector, it always combine function member function erase and std::remove or std::remove_if.
In vector, the function erase can just delete element by position, like:
iterator erase (iterator position);
iterator erase (iterator first, iterator last);
But if you want to erase elements with some condition, you can combine it with std::remove or std::remove_if.
For example, you want to erase all the elements 6 in the below vector:
std::vector<int> vec{6, 8, 10, 3, 4, 5, 6, 6, 6, 7, 8};
// std::remove move elements and return iterator for vector erase funtion
auto last = std::remove(vec.begin(), vec.end(), 6);
for(int a:vec)
cout<<a<<" ";
cout<<endl;
// 8 10 3 4 5 7 8 6 6 7 8
vec.erase(last, vec.end());
for(int a:vec)
cout<<a<<" ";
cout<<endl;
// 8 10 3 4 5 7 8
std::remove works as below, it does't erase any elements, it just move elements and returns the iterator.
Possible implementation:
template< class ForwardIt, class T >
ForwardIt remove(ForwardIt first, ForwardIt last, const T& value)
{
first = std::find(first, last, value);
if (first != last)
for(ForwardIt i = first; ++i != last; )
if (!(*i == value))
*first++ = std::move(*i);
return first;
}
Conclusion:
If you want to remove elements with some condition, you use vector::iterator erase (iterator first, iterator last); essentially.
First get range start:
auto last = std::remove(vec.begin(), vec.end(), equal_condition_value);
erase by range(always with end())
vec.erase(last, vec.end());
cited:
https://en.cppreference.com/w/cpp/algorithm/remove
Simplest I can come up with:
erase() is something you can do to an element in a container. Given an iterator/index into a container, erase( it ) removes the thing the iterator refers to from the container.
remove() is something you can do to a range, it re-arranges that range but doesn't
erase anything from the range.
remove doesn't "really" remove
anything, because it can't.
In order to "actually" remove the elements from container you need to access container APIs. Where as remove works only with iterators irrespective of what containers those iterators points to. Hence, even if remove wants an "actual remove", it can't.
Remove overwrite "removed" elements by the following elements that were not removed and then it is up to the caller to decide to use the returned new logical end instead of the original end.
In your case remove logically removed 1 from vector a but size remained to 2 itself. Erase actually deleted the elements from vector. [ from vector new end to old end ]
The main idea of remove is it cannot change the number of elements and it just remove elements from a range as per criteria.

Idiomatic way to cheaply remove an element from an arbitrary container?

All C++ standard library containers have an insert() method; yet they don't all have a remove() method which does not take any arguments, but performs the cheapest possible removal at arbitrary order. Now, of course this would act differently for different containers: In a vector we would remove from the back, in a singly-list list we'd remove from the front (unless we kept a pointer to the tail), and so forth according to implementation details.
So, is there a more idiomatic way to do this other than rolling my own template specialization for every container?
Part of the design of the standard containers is that they ONLY provide operations as member functions if it is possible to provide one that is optimal (by chosen measures) for that container.
If a container provides a member function, that is because there is some way of implementing that function is a way that is optimal for that container.
If it is not possible to provide an optimal implementation of an operation (like remove()) then it is not provided.
Only std::list and (C++11 and later) std::forward_list are designed for efficient removal of elements, which is why they are the only containers with a remove() member function.
The other containers are not designed for efficient removal of arbitrary elements;
std::array cannot be resized, so it makes no sense have have either an insert() OR a remove() member function.
std::deque is only optimised for removal at the beginning or end.
Removal of an element from std::vector is less efficient than other containers, except (possibly) from the end.
Implementing a remove() member function for these containers therefore goes against the design philosophy.
So if you want to be able to efficiently remove elements from a container, you need to pick the right container for the job.
Rolling your own wrapper for the standard containers, to emulate operations that some containers don't support is simply misleading - in the sense of encouraging a user of your wrapper classes to believe they don't need to be careful with their choice of container if they have particular requirements of performance or memory usage.
So to answer your question
"So, is there a more idiomatic way to do this other than rolling my own template specialization for every container?
There are lot of ways to do remove
Sequence container and unordered container's erase() returns the next
iterator after the erased item.
Associative container's erase() returns nothing.
/*
* Remove from Vector or Deque
*/
vector<int> vec = {1, 4, 1, 1, 1, 12, 18, 16}; // To remove all '1'
for (vector<int>::iterator itr = vec.begin(); itr != vec.end(); ++itr) {
if ( *itr == 1 ) {
vec.erase(itr);
}
} // vec: { 4, 12, 18, 16}
// Complexity: O(n*m)
remove(vec.begin(), vec.end(), 1); // O(n)
// vec: {4, 12, 18, 16, ?, ?, ?, ?}
vector<int>::iterator newEnd = remove(vec.begin(), vec.end(), 1); // O(n)
vec.erase(newEnd, vec.end());
// Similarly for algorithm: remove_if() and unique()
// vec still occupy 8 int space: vec.capacity() == 8
vec.shrink_to_fit(); // C++ 11
// Now vec.capacity() == 4
// For C++ 03:
vector<int>(vec).swap(vec); // Release the vacant memory
/*
* Remove from List
*/
list<int> mylist = {1, 4, 1, 1, 1, 12, 18, 16};
list<int>::iterator newEnd = remove(mylist.begin(), mylist.end(), 1);
mylist.erase(newEnd, mylist.end());
mylist.remove(1); // faster
/*
* Remove from associative containers or unordered containers
*/
multiset<int> myset = {1, 4, 1, 1, 1, 12, 18, 16};
multiset<int>::iterator newEnd = remove(myset.begin(), myset.end(), 1);
myset.erase(newEnd, myset.end()); // O(n)
myset.erase(1); // O(log(n)) or O(1)

Which order is used to stack or heap variable creation [duplicate]

This question already has an answer here:
How do I erase elements from STL containers?
(1 answer)
Closed 8 years ago.
I've this code:
#include <algorithm>
#include <iostream>
#include <list>
using namespace std;
struct P
{
bool operator()(const int &n) const
{
return n % 3 == 0;
}
};
int main()
{
std::list<int> l({ 5, 2, 6, 1, 13, 9, 19 });
std::cout << l.size();
std::remove_if(l.begin(), l.end(), P());
std::cout << l.size() << std::endl;
return 0;
}
prints out "77". I expected it would have printed out "75", because the operator () of the P struct, returns true when its argument has not remainder of the division by 3. And that's the case for '6' and '9' (two elements out of seven).
Am I missing something ?
thanks.
To quote from http://www.cplusplus.com/reference/algorithm/remove_if/
The function cannot alter the properties of the object containing the range of elements (i.e., it cannot alter the size of an array or a container): The removal is done by replacing the elements for which pred returns true by the next element for which it does not, and signaling the new size of the shortened range by returning an iterator to the element that should be considered its new past-the-end element.
In other words, it rearranges the elements in the given range so that all the non-removed ones are at the beginning, then returns an iterator just past the end of the non-removed part. But it can't delete any elements, because it doesn't know anything about the underlying container.
Is it possible std::remove_if returns the resulting list?
remove/remove_if only reorders a sequence, it doesn't modify it. Iterators have no access to or knowledge of the container from which they come. You need to pass the result to a suitable erase container member:
l.erase(std::remove_if(l.begin(), l.end(), P()), l.end());
Don't forget the second l.end() so that you get the two-iterator overload of erase that erases a whole range. If you forget it, you end up with the one-iterator overload that only erases a single element.

STL remove doesn't work as expected?

int main()
{
const int SIZE = 10;
int a[SIZE] = {10, 2, 35, 5, 10, 26, 67, 2, 5, 10};
std::ostream_iterator< int > output(cout, " ");
std::vector< int > v(a, a + SIZE);
std::vector< int >::iterator newLastElement;
cout << "contents of the vector: ";
std::copy(v.begin(), v.end(), output);
newLastElement = std::remove(v.begin(), v.end(), 10);
cout << "\ncontents of the vector after remove: ";
//std::copy(v.begin(), newLastElement, output);
//this gives the correct result : 2 35 5 26 67 2 5
std::copy(v.begin(), v.end(), output);
//this gives a 10 which was supposed to be removed : 2 35 5 26 67 2 5 2 5 10
cout << endl;
return 0;
}
There are three 10 in the array a.
why does the array v contains a 10 after we remove the all the 10s with remove function.
you can see the compiled output also here
Actually std::remove doesn't remove the item from the container. Quoted from here
Remove removes from the range [first, last) all elements that are equal to value. That is, remove returns an iterator new_last such that the range [first, new_last) contains no elements equal to value. The iterators in the range [new_last, last) are all still dereferenceable, but the elements that they point to are unspecified. Remove is stable, meaning that the relative order of elements that are not equal to value is unchanged.`
That is, std::remove works with a pair of iterators only and does not know anything about the container which actually contains the items. In fact, it's not possible for std::remove to know the underlying container, because there is no way it can go from a pair of iterators to discover about the container to which the iterators belong. So std::remove doesn't really remove the items, simply because it cannot. The only way to actually remove an item from a container is to invoke a member function on that container.
So if you want to remove the items, then use Erase-Remove Idiom:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
The erase-remove idiom is so common and useful is that std::list has added another member function called list::remove which produces the same effect as that of the erase-remove idiom.
std::list<int> l;
//...
l.remove(10); //it "actually" removes all elements with value 10!
That means, you don't need to use erase-remove idiom when you work with std::list. You can directly call its member function list::remove.
The reason is that STL algorithms do not modify the size of the sequence. remove, instead of actually erasing items, moves them and returns an iterator to the "new" end. That iterator can then be passed to the erase member function of your container to actually perform the removal:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
By the way, this is known as the "erase-remove idiom".
EDIT: I was incorrect. See comments, and Nawaz's answer.
Because std::remove doesn't actually shrink the container, it just moves all the elements down to to fill up the spot used by the "removed" element. For example, if you have a sequence 1 2 3 4 5 and use std::remove to remove the value 2, your sequence will look like 1 3 4 5 5. If you then remove the value 4, you'll get 1 3 5 5 5. At no point does the sequence ever get told to be shorter.
C++20 introduces a new non-member function std::erase that simplifies this task for all standard library containers.
The solution suggested by multiple older answers here:
v.erase(std::remove(v.begin(), v.end(), 10), v.end());
Can now be written as:
std::erase(v, 10);