Why cannot this simple vector c++ program work? - c++

I am learning to use stl vector and It is odd that this program cannot work. What is wrong with it? How should I do if I want to implement the same function with vector?
#include <vector>
#include <iostream>
using namespace std;
int main()
{
vector<int> vec;
vector<int>::iterator it;
vector<int>::iterator temp;
it = vec.begin();
vec.insert(it, -1);
it++;
vec.insert(it, 2);
for(temp = vec.begin();temp!=vec.end();temp++)
cout<<*temp<<' ';
return 0;
}

vec.insert(it, -1); invalidates it.
You should rather use it = vec.insert(it, -1); which will keep it valid.
You can see the documentation:
https://en.cppreference.com/w/cpp/container/vector
section called "Iterator invalidation" or look at this great question and answer: Iterator invalidation rules

On executing the code
vector<int> vec;
You created an object named vec, it has no elements and vec.size() will be zero.
So what vec.begin() returns is the same as what vec.end() returns.
By doing vec.insert(it, -1); you are inserting a value out of vec's range.
That is undefined behavior.
No, vec.insert(it, -1) works well, but vec.insert(it, -1) causes the vector to reallocate memory for its first element.
That invalids it.
Try vec.emplace_back(-1) or vec.resize(2) instead. They extend vec's size and capacity.

Related

Erase all even numbers from vector using find_if [duplicate]

This question already has answers here:
Iterator invalidation rules for C++ containers
(6 answers)
Closed 5 years ago.
#include <iostream>
#include <vector>
#include <algorithm>
#include <time.h>
#include <iomanip>
using namespace std;
bool isEven(int n)
{
return n%2 == 0;
}
int main()
{
srand(time(NULL));
vector<int> myVec;
for(int i = 0; i < 20; i++)
{
myVec.push_back(rand() % 100);
}
while(1)
{
vector<int>::iterator q = std::find_if(myVec.begin(), myVec.end(), isEven);
cout << *q << endl;
if(q == myVec.end())
{
myVec.erase(q);
break;
}
else
myVec.erase(q);
}
return 0;
}
This code is giving segmentation fault. The above code is to remove all the even numbers from the vector using find_if and erase function
Please help. Any help will be highly appreciated.
EDIT: I have edited it to make sure that iterator will be valid always.
Still it is giving segmentation fault.
std::vector::erase invalidates all iterators to and after the point of erasure. You can't continue using that iterator, not to increment it, use it to access the vector, or even compare it to end().
The correct algorithm to use is std:remove_if. Unlike the name implies, it will only move all even items of the vector "to the back", without invalidating any iterators. It will return an iterator to the start of this sub-range, which you can then just feed to the appropriate erase overload (the one that accepts a pair of iterators).
This has been used so much in code that it's even named "the erase-remove idiom".
When using the erase(it); function the iterator changes so you need to set the iterator again to the new one returned by the erase function.
In your code, you are checking for the end if(q == myVec.end()) and then using erase this will throw an error as.end() does not point to data, and to be able to erase an item from the vector the iterator needs to be valid. So by changing if(q == myVec.end()) to if(q == (myVec.end()-1)) it will allow you to delete the last element in case of been a pair.

using iterator for vectors in a list

I am trying to use iterator in a list as follows, is this the right way to do it?
I have two vectors v1 and v2 and I am using two iterators it1 and it2. Later, I am using a list which is list<vector<int>::iterator> to push_back the iterators it1 and it2. This works, but if any one of the vector is empty, it crashes.
int main() {
vector<int> v1 ={1,2,3};
vector<int> v2 ={4,5,6,7};
vector<int>::iterator it1 = v1.begin();
vector<int>::iterator it2 = v2.begin();
list<vector<int>::iterator> l;
l.push_back(it1);
l.push_back(it2);
for(auto a : l){
vector<int>::iterator it = a;
while(*it){
cout<<*it<<endl;
it++;
}
}
return 0;
}
The crash is coming from trying to dereference it in the line while(*it){. If a vector v is empty, then the iterator v.begin() won't point to valid memory, and dereferencing it will cause a Segmentation Fault.
It will fail as you cannot dereference an iterator until you know its valid to dereference. If the vector is empty begin == end and end is not a valid thing to dereference, as it's one off the end of the container.
You wont be able to iterate your container without knowing the end and you don't capture it, you only capture begin. Simply dereferencing the iterator to test for validity is not correct. It could hold any value.
What about an alternative where you capture a pair of iterators for each vector?
#include <vector>
#include <list>
#include <iostream>
#include <utility>
using namespace std;
int main()
{
const vector<int> v1 ={1,2,3};
const vector<int> v2 ={4,5,6,7};
list<pair<vector<int>::const_iterator,
vector<int>::const_iterator>> L;
L.push_back(make_pair(begin(v1), end(v1)));
L.push_back(make_pair(begin(v2), end(v2)));
for(const auto& a : L){
for(auto it = a.first; it != a.second; ++it)
{
cout << *it << '\n';
}
}
}
Now you have the capability to stop as you know the end iterator too.
list<vector<int>::iterator> l;
l.push_back(it1);
If suppose v1 is empty, then it1 would be v1::end() which is one past the last element of vector and is not part of the vector.So later when you do
while(*it){
you are trying to dereference v::end() which is the reason for the crash.To avoid this you should insert into l only if the iterators are not pointing to end.
if(it1!= v1.end())
l.push_back(it1);

C++ - Why is program crashing with if statement inside map iterator?

I am new to C++ and I am trying to iterate through the map while passing an if statement through. However the program crashes.
Please help me fix the program.
#include <bits/stdc++.h>
#include <iostream>
#include <set>
#include <string>
#include <iterator>
using namespace std;
int main()
{
std::map<int,int> h;
std::map<int,int>::iterator it;
h[1] = 2;
h[4] = 5;
for(it = h.begin(); it !=h.end(); it++){
if (it->second > 4){
h.erase(it->first);
}
}
You're erasing element inside the for loop, and the iterator pointing to the removed element (i.e. it) will be invalidated. Then it++ will cause problem.
You could
for (it = h.begin(); it != h.end(); ) {
if (it->second > 4){
it = h.erase(it); // set it to iterator following the last removed element
} else {
++it;
}
}
Your iterator removes the element the iterator is pointing to.
When an element in a std::map is removed, all iterators to its are immediately invalidated.
The iterator is no longer valid after the element is removed. Afterwards, the for-loop attempts to increment the no-longer-valid iterator. This is why your code crashes.
The typical solution goes something like this:
for(it = h.begin(); it !=h.end(); ){
{
std::map<int,int>::iterator p=it;
++it;
if (p->second > 4){
h.erase(p->first);
}
}
Note, that the element is removed only after the iterator is already incremented.
You are blowing away the iterator. It becomes invalid as soon as you remove an element from the map.
Also, you you might want to change your iterator increment to ++it. Can provide a little speed boost.

Why adding to vector does not work while using iterator?

I have two code sample, which do exactly same thing. One is in C++03 and C++11.
C++ 11
int main()
{
vector<int> v = {1,2,3};
int count = 0;
for each (auto it in v)
{
cout << it<<endl;
if (count == 0)
{
count++;
v.push_back(4);//adding value to vector
}
}
return 0;
}
C++ 03
int main()
{
vector<int> v = {1,2,3};
int count = 0;
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it<<endl;
if (count == 0)
{
count++;
v.push_back(4);//adding value to vector
}
}
return 0;
}
Both the codes are giving following exception.
Now when I see vector::end() implementation,
iterator end() _NOEXCEPT
{
// return iterator for end of mutable sequence
return (iterator(this->_Mylast, this));
}
Here, inline function clearly takes _Mylast to calculate end. So, when I add, it pointer will be incremented to next location, like _Mylast++. Why I am getting this exception?
Thanks.
A vector stores its elements in contiguous memory. If that memory block needs to be reallocated, iterators become invalid.
If you need to modify the vector's size while iterating, iterate by index instead of iterator.
Another option is to use a different container with a different iterator behavior, for example a list will allow you to continue iterating as you insert items.
And finally, (dare I suggest this?) if you know the maximum size your vector will grow to, .reserve() it before iterating over it. This will ensure it doesn't get reallocated during your loop. I am not sure if this behavior is guaranteed by the standard though (maybe someone can chime in); I would definitely not do it, considering iterating by index is perfectly safe.
Your push_back is invalidating the iterator you're using in the for loop, because the vector is reallocating its memory, which invalidates all iterators to elements of the vector.
The idiomatic solution for this is to use an insert_iterator, like the one you get from calling std::back_insterter on the vector. Then you can do:
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> v;
auto inserter = std::back_inserter(v);
for(int i=0; i<100; ++i)
inserter = i;
for(const auto item : v)
std::cout << item << '\n';
}
And it will ensure its own validity even through reallocation calls of the underlying container.
Live demo here.

Vectors in C++ : Why i'm getting so much errors for this simple copy & print program?

i'm trying to use algorithm lib & vector lib to first copy a set of numbers from an array into a vector then printing it using iteration, where is the problem of my code?
and one thing is that i chose 2 way to do this iteration first using vec.begin() ; vec.end() method & the other one is for (i = 0 ; i < vec.capacity() ; i++)
both facing errors.
what should i do?
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int intArray[] = {5,6,8,3,40,36,98,29,75};
vector<int> vecList(9);
//vector<int>::iterator it;
copy (intArray, intArray+9,vecList);
//for(it = vecList.begin() ; it != vecList.end() ; it++)
for (int it = 0 ; it < vecList.capacity() ; it++)
{
cout<<*it<<endl;
}
system("pause");
return 0;
}
There are several improvements possible.
You confuse iterators with indices. An iterator it is a glorified pointer into the vector, that you need to derefence by typing *it. An index i is an offset from the beginning of the vector and saying vecList[i] will give you that element.
The initialization of the vector is best done using initializer lists (C++11), rather than reading from an array.
You need to loop to vecList.size(). The capacity of the vector is the size of the allocated storage space for the elements of the vector container. Looping is best done with a ranged-for loop as shown by Kerrek SB, or a std::for_each + a lambda expression, or a regular for loop as you did. In that case however, it's best to get into the habit of doing it != vecList.end() (instead of using <) and doing ++it instead of it++.
Note that I also used auto to avoid writing the explicit iterator type. It's also a good habit to get into using auto wherever you can.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
// initialize vector with a list of elements
vector<int> vecList {5,6,8,3,40,36,98,29,75};
// loop from begin() to end() of vector, doing ++it instead of it++
for (auto it = vecList.begin(); it != vecList.end(); ++it)
{
cout<<*it<<endl;
}
// the pause command is better done by setting a breakpoint in a debugger
return 0;
}
Output on Ideone (this uses the g++ 4.5.1 compiler, it's best to upgrade to at least that version to take advantage of C++11 features).
The problem is that you're confusing indexes and iterators.
w/ index:
for (int i = 0 ; i < vecList.size() ; it++)
{
cout<<vecList[i]<<endl;
}
w/ iterators
for (std::vector<int>::const_iterator it = vecList.begin() ; i != vecList.end() ; it++)
{
cout<<*it<<endl;
}
A. you need to iterate on vecList.size() not vecList.capacity() which mean how much memory the vector is reserving for himself (not how much of it is in use).
B. you tried to use the integer index it as an iterator with the call to *it, you should check Luchian Grigore answer for the right way to do it.
This isn't an answer, but I wanted to show how modern C++ allows you to do away with lots of the brittle dependencies on details:
int intArray[] = {5,6,8,3,40,36,98,29,75};
std::vector<int> vecList(std::begin(intArray), std::end(intArray));
for (int i : vecList) { std::cout << i << std::endl; }
Using iterators and algorithms idiomatically, you can often remove any explicit mention of details such as lengths of arrays, thus making your code more robust.
Typo mistake use : copy (intArray, intArray+9,vecList.begin());
so,
#include<iostream>
#include<vector>
#include <algorithm>
using namespace std;
int main()
{
int intArray[] = {5,6,8,3,40,36,98,29,75};
vector<int> vecList(9);
vector<int>:: iterator it;
copy (intArray, intArray+9,vecList.begin());
for (it=vecList.begin();it!=vecList.end(); it++)
{
cout<<*it<<endl;
}
system("pause");
return 0;
}