Set iterator got invalidated? - c++

there is something I don't really understand. Why in the following code I have different value of *it? Before loop it is 1, and after loop it is 5
set <int> my_set{3,1,4,2,5};
set<int>::iterator it = my_set.begin();
cout << "beginning of set " << *it << endl;
for(; it != my_set.end(); ++it)
cout << *it << endl;
cout << "Beginning of set " << *it << endl;

Related

why is the iterator showing address instead of value in the loop? [duplicate]

This question already has answers here:
Iterator invalidation rules for C++ containers
(6 answers)
Closed 3 months ago.
`
vector<int> nums;
nums.push_back(1);
nums.push_back(2);
nums.push_back(3);
vector<int> res;
res.push_back(nums.front());
vector<int>::iterator it = nums.begin();
vector<int>::iterator it2 = res.begin();
++it;
cout << "it2 -> " << *it2 << endl;
cout << "it + it2 " << *it + *it2 << endl;
while(it != nums.end())
{
res.push_back(*it + *it2);
cout << "it : " << *it << endl;
cout << "it2 : " << *it2 << endl;
cout << "pushed " << (*it + *it2) << " ";
it++;
it2++;
}
it = nums.begin();
while(it != nums.end())
{
cout << *it << " ";
++ it;
}
cout << endl;
it2 = res.begin();
while(it2 != res.end())
{
cout << *it2 << " ";
++it2;
}
cout << endl;
`
The output of the above is :
it2 -> 1
it + it2 3
it : 2
it2 : 17858448
pushed 17858450 it : 3
it2 : 17825984
pushed 17825987 1 2 3
1 3 17825987
I can't understand why the value of *it2 is normal outside the loop but inside it, it's showing the address.
I was trying to find the running sum of a 1d array using vectors. I learning iterators and hence am interested in understanding exactly why the above code is not working.
Those aren't addresses, they are garbage integers.
Your code is suffering from iterator invalidation. When you add an item to a vector you potentially invalidate any iterator that is pointing to it. This happens because adding an element to a vector may cause the vector to reallocate the memory it uses to hold it's elements. If this happens then you are left with an iterator that is no longer pointing at the correct memory, so you get garbage values.
The simple fix is to use integer offsets instead of iterators for this code
vector<int>::iterator it = nums.begin();
size_t off2 = 0;
++it;
cout << "res[off2] -> " << res[off2] << endl;
cout << "it + res[off2] " << *it + res[off2] << endl;
while(it != nums.end())
{
res.push_back(*it + res[off2]);
cout << "it : " << *it << endl;
cout << "res[off2] : " << res[off2] << endl;
cout << "pushed " << (*it + res[off2]) << " ";
it++;
off2++;
}
Although since you seem to be always using the last item from res an even simpler fix would be to use res.back(). Without the printing that gives
vector<int>::iterator it = nums.begin();
++it;
while(it != nums.end())
{
res.push_back(*it + res.back());
it++;
}
An earlier version of this post was incorrect, thanks to Pepijn for putting me straight.

Can I print each map value with a for loop with this code?

I hope you can help me out with my idea or something better (C++). Im trying to print out the second values of a map into a for loop which will already print out the first values of another map. Is it possible to do it with find like im trying here: (thanks in advance)
map1:
map<double, int> map1 = {
{51.5, 29},
{25.2, 87},
{13.4, 91},
{89.2, 100},
{7.4, 85} };
map<string, int> map2;
for (int i = 0; i < 5; i++){
cout << "Ingrese cadena " << cont++ << ": " << endl;
cin >> cadena;
map2[cadena];
}
cout << endl;
cout << "Desplegar map2" << endl;
for(map<string, int>::iterator mapear = map2.begin(); mapear != map2.end(); ++mapear){
cout << mapear->first << " " << map1.find(51.5)->second << endl;
}
cout << endl;
This will print out in a certain order by the key order of the 2 maps, respectively.
cout << "Desplegar map2" << endl;
auto iter1 = map1.begin();
auto iter2 = map2.begin();
for (int i = 0; i < 5; i++) {
cout << iter2->first << " " << iter1->second << endl;
iter1++;
iter2++;
}
cout << endl;

STL std::find() C++

In the below code I declared a vector as {1,2,3,4,5}.
Using the STL std::find(), I am trying to find 5 in the vector ranging from arr.begin() to arr.end()-1 or arr.begin() to arr.begin()+4 which is the same range from 1 to 4.
But here for both, iterators are return pointing to 5. Why is that since the range is only from 1 to 4?
#include <iostream>
#include <vector>
#include <array>
#include <algorithm>
using namespace std;
int main () {
vector<int> arr {1,2,3,4,5};
// TEST
for_each(arr.begin(), arr.begin()+4, [](const int &x) { cerr << x << " "; }); cerr << endl;
for_each(arr.begin(), arr.end()-1, [](const int &x) { cerr << x << " "; }); cerr << endl;
auto it1 {std::find(arr.begin(), arr.begin()+4, 5)};
auto it2 {std::find(arr.begin(), arr.end()-1, 5)};
if (it1 != arr.end())
cout << *it1 << " Found!" << endl;
else
cout << "NOT Found!" << endl;
if (it2 != arr.end())
cout << *it2 << " Found!" << endl;
else
cout << "NOT Found!" << endl;
return 0;
}
OUTPUT:
1 2 3 4
1 2 3 4
5 Found!
5 Found!
std::find just returns the iterator passed as the 2nd argument when the element is not found. So it returns the iterators as arr.begin()+4 or arr.end()-1 in your code.
You shouldn't compare it with std::end, e.g.
if (it1 != arr.begin()+4)
cout << *it1 << " Found!" << endl;
else
cout << "NOT Found!" << endl;
if (it2 != arr.end()-1)
cout << *it2 << " Found!" << endl;
else
cout << "NOT Found!" << endl;
It is because if std:find does not find the requested value (as it occurs here), it returns the end iterator you give to it (not the end iterator of the full vector), which in this case points to the element you are looking for.

std::cout for map<string, int>

I have a map declared as follows
map<string, int> symbolTable;
if(tempLine.substr(0,1) == "("){
symbolTable.insert(pair<string, int>(tempLine, lineCount));
}
How do I std::cout all of the things in my symbol table?
In modern C++:
for (auto&& item : symbolTable)
cout << item.first << ": " << item.second << '\n';
If you only have access to a pre-C++11 compiler the code would be:
for ( map<string, int>::const_iterator it = symbolTable.begin(); it != symbolTable.end(); ++it)
cout << it->first << ": " << it->second << '\n';
Here's an alternative if your compiler isn't C++11 compliant:
for (map<string, int>::iterator it = symbolTable.begin();
it != symbolTable.end(); ++it)
{
cout << it->first << " " << it->second << endl;
}
And for completeness, if it is:
for (auto& s : symbolTable)
{
cout << s.first << " " << s.second << endl;
}
You can use a loop to print all the key/value pairs. The code following is an example in C++11
for (const auto& kv : symbolTable) {
std::cout << kv.first << " " << kv.second << '\n';
}
ps: Both of other two answers pay little attention to const, which is quite sad...

mingw g++ vector<T>::insert bug

vector<int> nums;
nums.push_back(0);
nums.push_back(1);
nums.push_back(2);
nums.push_back(3);
vector<int>::iterator it = nums.begin();
it++;
cout << "it points to " << *(it) << endl;
for(vector<int>::iterator jt = nums.begin(); jt != nums.end(); jt++) {
cout << (*jt) << endl;
}
cout << endl;
nums.insert(it, 100500);
cout << ">> insert(it, 100500)" << endl << endl;
cout << "it points to " << *(it) << endl;
for(vector<int>::iterator jt = nums.begin(); jt != nums.end(); jt++) {
cout << (*jt) << endl;
}
cout << endl;
it++;
cout << ">> it++" << endl << endl;
cout << "it points to " << *(it) << endl;
for(vector<int>::iterator jt = nums.begin(); jt != nums.end(); jt++) {
cout << (*jt) << endl;
}
cout << endl;
nums.insert(it, 100800);
cout << ">> insert(it, 100800)" << endl << endl;
cout << "it points to " << *(it) << endl;
for(vector<int>::iterator jt = nums.begin(); jt != nums.end(); jt++) {
cout << (*jt) << endl;
}
cout << endl;
it++;
cout << ">> it++" << endl << endl;
cout << "it points to " << *(it) << endl;
for(vector<int>::iterator jt = nums.begin(); jt != nums.end(); jt++) {
cout << (*jt) << endl;
}
cout << endl;
returns
it points to 1
0
1
2
3
>> insert(it, 100500)
it points to 1
0
100500
1
2
3
>> it++
it points to 2
0
100500
1
2
3
>> insert(it, 100800)
it points to 100800
134352185
0
100500
1
2
3
>> it++
it points to 2
134352185
0
100500
1
2
3
I cant understand anything. help!
mingw g++ 4.5.0 win32
When you insert a new element into a vector, any iterators to elements after the insertion position are invalidated and if a reallocation occurs then all iterators into the container are invalidated. A reallocation occurs any time that v.capacity() - v.size() is less than the number of elements you are trying to insert.
When an iterator is invalidated, it means that the iterator can no longer be used. It is invalid.
This overload of insert returns a new iterator to the inserted element, so you can replace this:
nums.insert(it, 100500);
with this:
it = nums.insert(it, 100500);
The rules for when iterators are invalidated are different for each container and you must be careful to understand them. One of the best references for the STL is the SGI STL documentation. The iterator invalidation rules are usually listed in a footnote on each of the container documentation pages.
Note that the SGI STL documentation is not the official documentation for the C++ Standard Library and there are some subtle differences, but usually those differences are not particularly important; one thing to note is that some pieces of the SGI STL are not included in the C++ Standard Library and some parts of the C++ Standard Library are not part of the SGI STL.
This is not a bug. You failed to properly read the std::vector documentation before leaping to the conclusion that the software was in error; in fact, vector insertions invalidate all iterators.