std::list insert() invalidates iterator? [duplicate] - c++

This question already has answers here:
How to invalidate an iterator?
(4 answers)
What is iterator invalidation?
(3 answers)
Closed 4 years ago.
Say I have a simple program as so:
int main(void) {
std::list<int> l;
auto it = l.begin();
auto it2 = l.insert(l.begin(), 5);
std::cout << (it == it2) << std::endl;
}
Doesn't this show that the iterator it has been invalidated by inserting into the list. Yet the C++ standard says that insertion into a list does not invalidate iterators.
Originally it would probably hold a nullptr since the list was empty. Now it no longer points to any iterator part of the list. So is it not invalidated?

Related

Runtime exception when using vector.insert() [duplicate]

This question already has answers here:
Vector iterator erase giving me a runtime error?
(2 answers)
Replacing elements in vector using erase and insert
(3 answers)
Erasing from a std::vector while doing a for each?
(1 answer)
Closed 1 year ago.
So I have the following code, which is supposed to use an iterator to replace an element in a vector if it matches some given value "old".
using StringIter = std::vector<std::string>;
using StringVec = std::vector<std::string>;
void replace(StringVec ref, std::string old, std::string replacement)
{
for (StringIter::iterator it = ref.begin(); it != ref.end(); it++)
{
if (*it == old)
{
ref.erase(it);
ref.insert(it,replacement);
}
}
}
However, I get the following runtime error: "vector emplace iterator outside range". I've tried changing the order of erase and insert, and using insert(it-1,...) instead, but it doesn't work. Haven't found any solution to this exact problem after an hour or so of googling.

Strange behaviour of m.erase() function in c++? [duplicate]

This question already has answers here:
map.erase( map.end() )?
(4 answers)
Closed 2 years ago.
int main(){
map<int, int> m;
m.insert({1,2});
m.insert({2,3});
m.insert({5,10});
m.erase(m.find(3));
for(auto &x: m){
cout<<x.first<<" "<<x.second<<nl;
}
}
Output:
1 2
5 10
As far as I know m.find(3) returns iterator to the m.end() if key is not found. Then why pair {2,3} is deleted?
The pair is deleted because you violated a pre-condition of std::map::erase
iterator erase( const_iterator pos );
iterator erase( iterator pos );
The iterator pos must be valid and dereferenceable. Thus the end()
iterator (which is valid, but is not dereferenceable) cannot be used
as a value for pos.
Violating a pre-condition of a standard library function has undefined behavior. So deleting a seemingly random element is totally in line with that.

Does modifying a std::vector invalidate an iterator? [duplicate]

This question already has answers here:
Iterator invalidation rules for C++ containers
(6 answers)
Closed 2 years ago.
Consider this piece of code:
#include <vector>
#include <iostream>
int main(int argc, char** args)
{
std::vector<int> vec;
vec.push_back(0);
for (auto iter = vec.begin(); iter != vec.end(); iter++)
{
vec.push_back((*iter) + 1);
std::cout << *iter << std::endl;
}
}
I expected this to print all the numbers to Infinite. But what it did was to print a LOT of zeros (and an occasional -256, WHAT?) only to run into a segfault.
My assumtion is that iter still points to the old array after the call to vec.push_back moves the internal data to a new array.
What exactly is the problem here? Is my assumption correct, that the push_back call invalidates the iterator?
Interestingly, when I substitute std::vector for a std::list, the code works as expected. Is it save to use a std::list instead? Or is that just working correctly by accident?
std::vector::push_back invalidates all iterators on that vector if the new vector size is greater than the previous capacity. (The reason is due to the reallocation of the vector).
The behaviour of using an invalidated iterator is undefined.
std::list::push_back does not invalidate any iterators.

Does std::next check if we are already at the end of the container? [duplicate]

This question already has answers here:
std::next with n > std::distance(it, c.end())
(3 answers)
Closed 5 years ago.
Suppose I have an iterator std::list::iterator it = mylist.begin() of a container, and I call
iterator it2 = std::next(it,1);
Does std::next check if it == mylist.end()?
No, the program was blocking in that situation. You should check yourself:
if (it != mylist.end())
it2 = std::next(it,1);

Delete all entries in STL Map which matches value [duplicate]

This question already has answers here:
How to remove from a map while iterating it?
(6 answers)
Erase/Remove contents from the map (or any other STL container) while iterating it
(9 answers)
Closed 8 years ago.
I'm trying to delete all entries in a map where value == 50 for any key.
This code is working fine for me.
while (itr != mymap.end())
{
if ((*itr).second == 50)
mymap.erase(itr++);
else
itr++;
}
But this code is giving run time error.
while (itr != mymap.end())
{
if ((*itr).second == 50)
{
mymap.erase(itr);
itr++
}
else
itr++;
}
My doubt is aren't both logic is same? why run time error in second case?
No, the logic is not the same.
In the first case the iterator is postincremented before erasing the element when it is a valid iterator.
In the second case the iterator is postincremented after erasing the element when it is an invalid iterator.
The common approach to this operation is the following
while ( itr != mymap.end() )
{
if ( (*itr).second == 50 )
itr = mymap.erase( itr );
else
itr++;
}
According to the C++ Standard (23.2.4 Associative containers)
9 The insert and emplace members shall not affect the validity of
iterators and references to the container, and the erase members
shall invalidate only iterators and references to the erased
elements.