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.
Related
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.
I am trying to understand std::find(). Below is my code.
std::set::find searches the container for an element equivalent to
val and returns an iterator to it if found, otherwise it returns an
iterator to set::end.
But when I gave find(100) I am getting 7 rather than 20.
#include <iostream>
#include <set>
using namespace std;
int main()
{
set <int> s1{20, 7, 2};
s1.insert(10);
s1.insert(5);
s1.insert(15);
s1.insert(1);
cout << "size() : " << s1.size() << endl;
cout << "max_size() : " << s1.max_size() << endl;
cout << "empty() : " << s1.empty() << endl;
for(auto itr = s1.begin(); itr != s1.end(); itr++)
cout << *itr << " ";
cout << endl;
cout << endl << "---- find(value) ----" << endl;
auto a1 = s1.find(10);
//cout << "find(10) : " << a1 << " " << *a1 << endl;
cout << "find(10) : " << *a1 << endl;
auto a2 = s1.find(100);
cout << "find(100) : " << *a2 << endl;
cout << endl << "---- count(value) ----" << endl;
cout << "s1.count(10) : " << s1.count(10) << endl;
cout << "s1.count(100) : " << s1.count(100) << endl;
return 0;
}
Output:
size() : 7
max_size() : 107374182
empty() : 0
1 2 5 7 10 15 20
---- find(value) ----
find(10) : 10
find(100) : 7
---- count(value) ----
s1.count(10) : 1
s1.count(100) : 0
The problem is that you're dereferencing an iterator a2 that points to s1.end() leading to undefined behavior. This problem arose because you're not checking before dereferencing the iterators, if the element was found or not.
To solve this you should add an explicit check before dereferencing the iterators.
//dereference only if the element was found
if(a2!=s1.end())
{
std::cout << "find(100) : " << *a2 << std::endl;
}
//otherwise print a message saying element not found
else
{
std::cout<<"element not found"<<std::endl;
}
auto a2 = s1.find(100);
cout << "find(100) : " << *a2 << endl;
Here you dereference (*a2) the end iterator. That is undefined behaviour - remember that s1.end() points to one past the last element and must not be dereferenced.
You're unlucky that you got a value from that dereference - it would be more convenient if your program crashed or otherwise reported the problem. But UB doesn't have to be diagnosed in any way.
You might have spotted the problem if you had run your program using Valgrind's memory checker (or your preferred equivalent). But there's a good chance that's unable to detect it (if the set has over-allocated, which is likely).
The value 100 is not present in the set. So this call
auto a2 = s1.find(100);
returns the iterator s1.end(). You may not dereference the iterator. This statement
cout << "find(100) : " << *a2 << endl;
invokes undefined behavior.
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;
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.
I am using pair in set and want to print values and my compiler always shows errors in "code 1" but it runs successfully in "code 2" .
I know that, these two procedure are same to access a set without a pair, but i faced problem using pair into a set.
I am using Windows 10 + Intel and using "codeblocks" IDE.
code 1:
set < pair< int,int> >::iterator it;
for(it=st.begin();it!=st.end();it++){
cout << *(it.first) << " " << *(it.second) << endl ;//error shows here
}
code 2:
set< pair < int,int > >::iterator it;
for(it : st){
cout << it.first << " " << it.second << endl ;
}
In "code 2", my program runs successfully but in "code 1" it shows error pointed to the commented line.
it is an iterator refering to a pair, In order to access the pair you need to dereference the iterator first.
cout << (*it).first << " " << (*it).second << endl ;
or better
cout << it->first << " " << it->second << endl ;
EDIT: If you have c++17 support.
for(auto [first, second] : st)
std::cout<<first<<" "<<second;