C++ List Iteration and erasing [duplicate] - c++

This question already has answers here:
iterate vector, remove certain items as I go
(3 answers)
Closed 6 years ago.
EDIT: This question refers specifically to std::lists - other similar questions on Stack Overflow refer to std::vectors
I'm using C++ and having trouble erasing an element from a std::list while iterating through it. I have a list of a custom class ('Objects' for the sake of this question), and my code looks like this:
for(auto i : Objects)
if(i.EraseFlag == true)
{
i = Objects.erase(i);
}
I'm getting the error: 'no matching function for call to std::list::erase(Object&)'
I believe this is the right way (as of C++11) to iterate through lists, erase an element and return an iterator that takes into account the erasure, but clearly I'm doing something wrong. Previously when using vectors I would use 'Objects.erase(Objects.begin() + i)' with i being an integer in a for loop, but given the access requirements of lists this won't work.
Help appreciated.
Thanks

Member function erase deals with iterators.
For such a task it would be correctly to use an ordinary for loop. For example
for ( auto it = Objects.begin(); it != Objects.end(); )
{
if ( it->EraseFlag ) it = Objects.erase( it );
else ++it;
}
Another approach is to use member function remove_if. For example
Objects.remove_if( []( const auto &value ) { return value.EraseFlag; } );

Related

C++ map container erase() segmentation fault [duplicate]

This question already has answers here:
How to remove from a map while iterating it?
(6 answers)
Closed 2 years ago.
I use this code to remove elements from map container that equal to some int.
for(auto x:m){
if((x.second)==element)m.erase(x.first);
}
As result Segmentation fault. I also tried this:
for(map<int,int>::iterator i=m.begin();i!=m.end();i++){
if((i->second)==element)m.erase(i);
}
Same result. If you put i++ into if/else program will freeze/loop or something. How can I fix this?
erase() invalidates the iterator being used by the for loop. Fortunately, erase() itself returns an iterator to the next entry, so the correct loop would look like this instead:
for (map<int,int>::iterator i = m.begin(); i != m.end(); )
{
if (i->second == element)
i = m.erase(i);
else
++i;
}
In addition to #john's answer, if your C++ Standard Library implementation supports it, you can invoke the std::erase_if(map, condition) helper:
std::erase_if(m, [](const auto& item) {
auto const& [key, value] = item;
// Write your erasing condition here, e.g.:
// return value == element;
});

Delete elements from a vector in C++11 while iterating over it [duplicate]

This question already has answers here:
Erasing elements from a vector
(6 answers)
Closed 6 years ago.
My applications requires to iterate over a vector and delete certain elements which doesnt satisfy the requirements. Which is the most correct way? I believe the following way is incorrect.Reason: I am getting segmentation fault.
std::vector<ObjectX> vec1;
//Fill in vec1
std::vector<ObjectX>::iterator itVec1 = vec1.begin();
for(;itVec1 != vec1.end(); ++itVec1) {
if (Oracle(*itVec1)) vec1.erase(itVec1);
}
When you call
vec1.erase(itVec1);
you invalidate itVec1. After that, ++itVec1 is not right. It leads to undefined behavior. You need to change your code a little bit.
for( ; itVec1 != vec1.end(); ) {
if (Oracle(*itVec1))
{
itVec1 = vec1.erase(itVec1);
}
else
{
++itVec1;
}
}
You can remove all the boiler plate code by using the Erase-Remove Idiom:
vec1.erase(std::remove_if(vec1.begin(), vec1.end(), Oracle), vec1.end());
You could just put the correct items into a new vector.

go through map c++ [duplicate]

This question already has answers here:
How can I loop through a C++ map of maps?
(9 answers)
Closed 9 years ago.
So, I have an std::map<int, my_vector> and I want to go through each int and analyse the vector.
I haven't gotten to the part of analyzing the vector just yet, I'm still trying to figure out how to go through every single element on the map.
I know it is possible to have an iterator, but I didn't quite understood how it works, also, I don't know if there isn't a better way to do what I intend to do
You can simply iterate over the map. Each map element is an std::pair<key, mapped_type>, so first gives you the key, second the element.
std::map<int, my_vector> m = ....;
for (std::map<int, my_vector>::const_iterator it = m.begin(); it != m.end(); ++it)
{
//it-->first gives you the key (int)
//it->second gives you the mapped element (vector)
}
// C++11 range based for loop
for (const auto& elem : m)
{
//elem.first gives you the key (int)
//elem.second gives you the mapped element (vector)
}
Iterators are the perfect thing for this. Look around http://www.cplusplus.com/reference/map/map/begin/

Is there any way to validate the iterator of an STL container? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ Best way to check if an iterator is valid
Let's say I have a function which takes an iterator as its sole parameter as below.
void DoSomethingWithIterator(std::vector<int>::iterator iter)
{
// Check the pre-condition
assert( /* how to validate iter here? */ )
// Operate on iter afterwards
..
}
How do I know if iter is valid or not. By valid, I mean it points to a existing element inside the vector, e.g., from m_intVector.begin() to m_intVector.end().
In general, you can't do that. C++ types are designed to be maximally efficient and don't contain such additional information.
For example, vector's iterator is likely to be equivalent to a pointer to element (this is the case on my machine, using g++ 4.7.2).
> I mean it points to a existing element inside the vector, e.g., from m_intVector.begin() to m_intVector.end().
Sure. Just iterate through the contents of m_vector, and compare each iterator to iter.
for ( std::vector<int>::iterator it = m_intVector.begin (); it != m_intVector.end (); ++it )
if ( it == iter ) return true;
return false;
But I suspect that you won't want to pay for that kind of checking.

Post increment on set iterator [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
iterator validity ,after erase() call in std::set
When I iterate over a set and want to delete certain items the iterators are changed. This results in segfaults as the iteration fails after deletion. How can I overcome this problem?
std::set< std::pair<double,unsigned>, comparisonFunction> candidates;'
[...]
for( auto it = candidates.begin(); it != candidates.end(); ++it)
{
[...]
if ( some constraint satisfied)
{
candidates.erase(it);
}
}
I encounter a segfault when I use this code. My guess is that this is either due to the corrupted iterators or due to the fact, that the element to be deleted is the last element in some cases. Does a post increment on the iterator overcome this problem? Like this:
candidate.erase(it++);
Use the return value of erase:
it = candidates.erase(it);
Note that you must not increment it if you erase an element, otherwise your iterator could be invalidated.
for( auto it = candidates.begin(); it != candidates.end();)
{
if ( some constraint satisfied)
{
it = candidates.erase(it);
}
else
++it;
}
Also note that this wasn't possible in C++03, since erase didn't return any iterator. However, since you're using C++11 it shouldn't be a problem.
References
std::set::erase