Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
vector<int> v = { 1,2,3,4,5 };
for (auto beg = v.begin(); beg != v.end();++beg)
{
if (beg == v.begin())
v.push_back(50);
}
During run time, it says : "vector iterator not incrementable".
See std::vector::push_back.
If the new size() is greater than capacity() then all iterators and references (including the past-the-end iterator) are invalidated. Otherwise only the past-the-end iterator is invalidated.
In your example, beg is an iterator. It is being invalidated by the push_back, you cannot use it anymore.
As mentioned std::vector::push_back() may invalidate your iterator. Possible, but pretty ugly solution could be:
for (auto beg = v.begin(); beg != v.end();++beg)
{
if (beg == v.begin()) {
v.push_back(50);
beg = v.begin();
}
}
but your logic seems convoluted, why not push back just before the loop?
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
auto& kphist = this->kphist;
for (auto& it : kphist) {
it.second.aging(); // EXC-BAD-ACCESS
if(it.second.age > LAST_DAY){
kphist.erase(it.first);
continue;
}
}
kphist is a private member
Class A{
private:
unordered_map<int, KeyPointHistory> kphist;
}
The debugger shows all item in kphist is valid, how is it possible to have a bad reference inside the for loop. What possibly can go wrong?
From cppreference.com for std::unordered_map::erase(): References and iterators to the erased elements are invalidated. Other iterators and references are not invalidated. Thus, you cannot use std::unordered_map::erase() from within a range for loop (since this will try to increment an invalid iterator).
To avoid incrementing an invalidated iterator, you can simply increment first
and then erase using the original iterator:
for(auto i=map.begin(),end=map.end(); i!=end; ) { // no increment here
auto it=i++; // but here instead
if(must_remove(it))
map.erase(it);
}
In fact, since erase() returns the iterator to the next element, you can avoid the extra iterator it (thanks to Hurkyl to pointing this out in a comment):
for(auto i=map.begin(),end=map.end(); i!=end; ) { // no increment here
if(must_remove(i))
i = map.erase(i); // but here
else
++i; // or here instead
}
No need to make a list of keys of elements to be erased ...
Btw, why don't you use a std::map (rather than an std::unordered_map) as your key is an int (which is easily orderable)? Also, why do you make a reference kphist of a member variable of the same name?
You cannot erase the contents / iterator while you iterate over it and neither should you.
Save the element index in a different container and when you're done loop through that and erase the elements you got.
What possibly can go wrong?
Everything!
You can erase from an unordered_map by directly passing the iterator to the item to be erased. When you do so, erase() returns the subsequent iterator, so you can do something like this:
for (auto pos = kphist.begin(); pos != kphist.end(); ) {
it.second.aging();
if(it.second.age > LAST_DAY)
pos = kphist.erase(it);
else
++pos;
}
As a bonus, this will probably be a bit faster than passing the key to be erased--since you're providing the iterator, it can get to the item to be erased directly rather than re-hashing the key to find the position you already knew.
This question already has answers here:
How to remove from a map while iterating it?
(6 answers)
Closed 8 years ago.
I'm using Xcode with C++ 11 for a std::map. Some elements in my map have a flag that says they need to be removed.
I want to iterate through the map, erasing the flagged elements in O(n) time. The call to erase does not return an iterator. I have seen some kind of erase(it++) implementation, but I have no evidence that such a call can work since the iterator will become invalid after the erase operation but before the increment operation.
My current code seems so inefficient.
for(auto it = myMap.begin(); it != myMap.end(); ++it)
{
delete *it;
myMap.erase(it);
it = myMap.begin(); //how can I avoid iterating through the map again
}
From the online documentation:
"Iterators, pointers and references referring to elements removed by the function are invalidated. All other iterators, pointers and references keep their validity."
So maybe this:
for(auto it = myMap.begin(); it != myMap.end();)
{
auto itPrev = it;
++it;
if(shouldBeDeleted(*itPrev))
myMap.erase(itPrev);
}
Edit: The erase(it++) idea you mention is actually ok, because the increment occurs (and returns a copy of the old, pre-increment value) before erase() is called. It's in effect the equivalent of:
template<typename IteratorT>
IteratorT PostIncrement(IteratorT& it)
{
auto copy = it;
++it;
return copy;
}
for(auto it = myMap.begin(); it != myMap.end();)
myMap.erase(PostIncrement(it));
which amounts to the same thing as the other example. Incidentally, this is why you should normally use the prefix ++ with iterators; that copy operation is extra overhead, and you usually don't need it.
When std::map::erase() is passed an iterator, it returns an iterator to the next element that follows the element being erased. This allows you to continue your iteration without starting over.
Try this:
auto it = myMap.begin();
while (it != myMap.end())
{
if (it->flagged)
{
delete *it;
it = myMap.erase(it);
}
else
++it;
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 8 years ago.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Questions concerning problems with code you've written must describe the specific problem — and include valid code to reproduce it — in the question itself. See SSCCE.org for guidance.
Improve this question
I have some vector temp = {1,2,2,3,4}. How to find all elem = 2, save there positions in another vector and delete from the first one.
vector<int> another
vector<int>::iterator it;
for (it = temp.begin(); it != temp.end(); )
{
if (it == elem) { //?
another.push_back(it); //?
temp.erase(it++);
}
else
{
++it;
}
}
std::remove(vec.begin(), vec.end(), 2);
this should do the trick.
(Of course, to actually erase them from the vector, you have to write
vec.erase(std::remove(vec.begin(), vec.end(), 2), vec.end());
according to the erase-remove idiom.)
Edit: Just noticed:
save there positions in another vector
("with guns in there hands", right?) - basically that doesn't make a lot of sense, the positions will be invalidated when you remove the elements from the container...
To save the positions:
#include <iterator>
for (auto it = temp.begin(); it != temp.end(); ++it)
if (*it == 2)
another.push_back(std::distance(temp.begin(), it));
To erase:
#include <algorithm>
temp.erase(std::remove(temp.begin(), temp.end(), 2), temp.end());
This works for a larger class of containers than just vectors, thanks to the genericity of iterators.
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
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ Best way to check if an iterator is valid
I want to do something like this:
std::vector<int>::iterator it;
// /cut/ search for something in vector and point iterator at it.
if(!it) //check whether found
do_something();
But there is no operator! for iterators. How can I check whether iterator points at anything?
You can't. The usual idiom is to use the container's end iterator as a 'not found' marker. This is what std::find returns.
std::vector<int>::iterator i = std::find(v.begin(), v.end(), 13);
if (i != v.end())
{
// ...
}
The only thing you can do with an unassigned iterator is assign a value to it.
Though the iterators are considered as general form of pointers, they are not exactly the pointers. The standard defines Past-the-end iterator to indicate the search failure in containers. Hence, it is not recommended to check the iterators for NULL
Past-the-end values are nonsingular and nondereferenceable.
if(it != aVector.end()) //past-the-end iterator
do_something();
If you want to use iterator in a loop, the safest way to use it is in this fashion:
for (std::vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
do_smth();
}
I believe this should generally give you a good test:
if (iterator._Mycont == &MyContainer)
{
Probably a valid iterator!
}
You could do tests to make sure that the iterator does not equal the end...
iterator != MyContainer.end()
and:
iterator >= MyContainer.begin()