I have to read only the first two elements from an std::map.
Here's my code:
#include<iostream>
#include<map>
#include<iterator>
using namespace std;
int main() {
map<int,int> a;
map<int,int>:: iterator itr;
itr = a.begin();
cout<<itr->first<<" "<<itr->second<<endl;
next(itr);
cout<<itr->first<<" "<<itr->second<<endl;
return 0;
}
I'm getting this error:
next was not declared in the scope
what am I missing here and if there is a better way to do it?
For using std::next, you need to have at least C++11 compliant compiler.
std::next returns a new incremented iterator. So, you need to use its return value to get the incremented iterator i.e.:
itr = next( itr );
Right now, itr is pointing to the same element because the return value is not used.
If you meant to increment the itr without a new iterator then std::advance is a better candidate here i.e.:
std::advance( itr, 1 );
If you're using a pre-C++11 compiler then you can use increment operator like this:
itr++;
Or,
++itr;
Here's a live demo.
In addition, the map is uninitialized/empty and you're trying to access its elements that are not there and this would result in Undefined Behavior.
Relevant read:
Why is "using namespace std;" considered bad practice?
C++: "std::endl" vs "\n"
you should use itr++ to move itr forward to point next set of pairs. and you can access them by map->first; and map->second;
Related
In other words, what I mean to say is : Is itr+=2 a valid argument in c++ ?, where (itr is an iterator to first element of the set). If so, then the following piece of code should work:
In this piece if code, the code written in /comment section/ functions well, while the code not in comment section do not. Help me out to iterate alternate elements.
#include <bits/stdc++.h>
using namespace std;
int main()
{
set<int> s;
s.insert(5);
s.insert(7);
s.insert(8);
auto it=s.begin();
cout<<*it<<'\n';
it+=2;
cout<<*it<<'\n';
/*for(auto it=s.begin();it!=s.end();it++)
cout<<*it<<" ";*/
return 0;
}
Is itr+=2 a valid argument in c++?
It depends on the container type. For example, it would be perfectly valid for std::vector or std::array, but not for std::set. Each container, due to its nature, provides different types of iterators. std::set only provides BidirectionalIterator, which do not support jumping over arbitrary number of elements, only incrementation and decrementation.
However, you can use std::advance() from <iterator> library (or just increment the iterator twice). Beware that you must never increment end() iterator, so you need to take it into account in loop condition.
for(auto it=s.begin(); it != s.end() && it != std::prev(s.end()); std::advance(it, 2))
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);
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.
I have encountered a problem invoking the following code:
#include<deque>
using namespace std;
deque<int> deq = {0,1,2,3,4,5,6,7,8};
for(auto it = deq.begin(); it != deq.end(); it++){
if(*it%2 == 0)
deq.erase(it);
}
which resulted in a segmentation fault. After looking into the problem I found that the problem resides in the way the STL manages iterators for deques: if the element being erased is closer to the end of the deque, the iterator used to point to the erased element will now point to the NEXT element, but not the previous element as vector::iterator does. I understand that modifying the loop condition from it != deq.end() to it < deq.end() could possibly solve the problem, but I just wonder if there is a way to traverse & erase certain element in a deque in the "standard form" so that the code can be compatible to other container types as well.
http://en.cppreference.com/w/cpp/container/deque/erase
All iterators and references are invalidated [...]
Return value : iterator following the last removed element.
This is a common pattern when removing elements from an STL container inside a loop:
for (auto i = c.begin(); i != c.end() ; /*NOTE: no incrementation of the iterator here*/) {
if (condition)
i = c.erase(i); // erase returns the next iterator
else
++i; // otherwise increment it by yourself
}
Or as chris mentioned you could just use std::remove_if.
To use the erase-remove idiom, you'd do something like:
deq.erase(std::remove_if(deq.begin(),
deq.end(),
[](int i) { return i%2 == 0; }),
deq.end());
Be sure to #include <algorithm> to make std::remove_if available.
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;
}