I have declared a std::vector<int>
in my main function and would like to remove all even elements from it, but only by passing it's iterator to a function called remove_even
which accepts the start and end iterator of the container.
#include <iostream>
#include <algorithm>
#include <vector>
void remove_even(auto start, auto end) {
while(start != end) {
if(*start % 2 == 0)
// Remove element from container
}
}
int main() {
std::vector<int> vec = {2, 4, 5, 6, 7};
remove_even(vec.begin(), vec.end());
}
Is there a way of doing this in C++ or must I directly pass in my vector to the function ?
It is the class std::vector
itself that has the method erase
that allows to erase required elements in a vector.
All you can do using iterators is to call standard algorithm std::remove_if
that then to use the returned iterator in a call of the method erase
.
For example
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<int>::iterator remove_even( std::vector<int>::iterator first,
std::vector<int>::iterator last )
{
return std::remove_if( first, last, []( int x ) { return x % 2 == 0; } );
}
int main()
{
std::vector<int> vec = { 2, 4, 5, 6, 7 };
for ( int x : vec ) std::cout << x << ' ';
std::cout << std::endl;
vec.erase( remove_even( vec.begin(), vec.end() ), vec.end() );
for ( int x : vec ) std::cout << x << ' ';
std::cout << std::endl;
}
The program output is
2 4 5 6 7
5 7
This is the correct way IMO:
template <typename T>
T remove_even(T start, T end) {
return std::remove_if(start,end,[](const auto& item){return item%2==0;};
}
int main() {
std::vector<int> vec = {2, 4, 5, 6, 7};
vec.erase(remove_even(vec.begin(), vec.end()),vec.end());
}
From cplusplus.com:
An iterator is any object that, pointing to some element in a range of elements (such as an array or a container), has the ability to iterate through the elements of that range using a set of operators (with at least the increment (++) and dereference (*) operators).
As stated in the quote, it points to an element in a range of elements. It does not need to provide any information about the range it is in, i.e. about the container the elements are stored in.
As already stated in a comment, removing an element from a vector (or any other container) is an operation that affects the container, not only the object. So you will always have to call erase()
or a similar function on the container.
What you are asking about is (somewhat, not exactly) similar to this:
void remove_or_not(int& i){
//do something with i to remove it from a container
//but we dont have a container here
}
int main(){
std::vector<int> vec;
//fill vec and generate some int n
remove_or_not(vec[n]);
}
When calling remove_or_not()
in the above example, we just pass a reference to an int - we totally lost the information that it is inside a container, so it's obvious we can't remove it from any container.
When trying the same with iterators we still have the information that the element is inside a container - but we might have lost the information in which container, as it is not required by the iterator to keep this information.
E.g. an iterator over a C-style array can just be a pointer. We can increment and decrement it and compare it to a pointer to the first element and a pointer behind the last element. But there is no need to know anything about the size of the array or about the array at all.
PS: for approaches how to correclty implement what you need, see the already posted answers, i don't think theres a need to repeat those.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With