Reputation: 715
I'm new to stl in c++ and I want to iterate over a vector of maps. Then, if one of these maps satisfies a certain condition, I want to make a copy of this map an then insert the copy into the vector.
For example:
int main(){
vector<map<string, int> > my_vector;
map<string, int> my_map;
my_map["zero"] = 0;
my_vector.push_back(my_map);
for(vector<map<string, int> >::iterator iter1 = my_vector.begin();
iter1 != my_vector,end();
iter1++){
for(map<string, int>::iterator iter2 = (*iter1).begin();
iter2 != (*iter1).end();
iter2++){
if(iter2->second == 0){
// make a copy of the map (*iter1), make some changes on it,
// then insert the copy in the vector
}
}
}
return 0;
}
I have tried with:
map<string, int> new_map = *iter1;
new_map["zero"]++; // to avoid an infinite loop
my_vector.push_back(new_map);
But the program crashes. No compiler error, only a program crash. Then I found this question and answers in stackoverflow, so I tried another way like this:
int main(){
vector<map<string, int> > my_vector;
map<string, int> my_map;
my_map["zero"] = 0;
my_vector.push_back(my_map);
int remaining = my_vector.size();
int current_position = 0;
while(remaining>0){
for(map<string, int>:: iterator iter1 = my_vector[index].begin();
iter1 != my_vector[index].end();
iter1++){
if(iter1->second == 0){
map<string, int> new_map = my_vector[0];
new_map["zero"]++; // to avoid an infinite loop
my_vector.push_back(new_map);
}
}
index++;
remaining = my_vector.size()-index;
}
return 0;
}
But the program is still crashing, so I think the problem (or one of the problems) would be not only the iterator, but also the "copy" of the map.
If anyone have an idea of how I should do this, I will really appreciate it.
Upvotes: 0
Views: 1944
Reputation: 466
This is my solution. It uses C++11 (because it looks so much better). Especially with collections C++11 gives the workflow a real boost.
#include <vector>
#include <string>
#include <map>
#include <iostream>
using namespace std ;
void merge(vector<map<string,int>>& from, vector<map<string,int>>& to)
{
for(auto entry : from) {
to.push_back(entry) ;
}
}
void search(vector<map<string,int>>& vec)
{
int iCount = 0 ;
vector<map<string, int>> cVector ;
for(auto vmap : vec) {
for(auto mapentry : vmap) {
if(mapentry.second == 0) {
iCount++ ;
map<string, int> new_map = vmap ;
cVector.push_back(new_map) ;
}
}
}
cout << "iCount: " << iCount << endl ;
merge(cVector, vec) ;
}
int main(){
vector<map<string, int> > my_vector;
map<string, int> my_map;
my_map["zero"] = 0;
my_map["third"] = 2 ;
my_map["second"] = 0 ;
my_vector.push_back(my_map);
cout << my_vector.size() << endl ;
vector<map<string,int>> cVector ;
search(my_vector) ;
cout << my_vector.size() << endl ;
return 0;
}
As written by Alex Antonov the push_back
invalidates your Iterator because the memory gets reallocated. My answer creates a new vector and copies the entries after the search back in the original vector (my_vector).
About range base for-loops see this.
Upvotes: 0
Reputation: 942
Your program may crash because push_back
can invalidate iterators. For example if a call to push_back
leads to memory reallocation (it happens when you exceed current capacity
of the vector
) then all vector
's iterators become invalid (they point to deallocated memory).
To solve that problem you can use indexes instead of iterators to access the vector
's elements or you can push_back
new elements to another copy of the vector
.
In other words: don't use an old vector::iterator
after you push_back
'ed a new element into the vector
.
Upvotes: 2
Reputation:
I probably have the wrong idea, but I think you can do something like this. You iterate over the elements of the vector, use the predicate to see if a current element fits the criteria, then use back_inserter
.
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
int main(){
vector<map<string, int> > my_vector;
map<string, int> my_map;
my_map["zero"] = 0;
my_vector.push_back(my_map);
auto predicate = [](const map<string, int>& cur) {
for (const auto& pair : cur)
{
if (pair.second == 0)
return true;
}
return false;
};
std::copy_if(my_vector.begin(), my_vector.end(), back_inserter(my_vector), predicate);
return 0;
}
Upvotes: 0
Reputation: 12715
One way you can do is:
size_t orig_size = my_vector.size();
for( size_t i = 0; i < orig_size; i++ ) {
//...
}
Other way:
Build a new vector and then afterwards append the contents of this new vector to the original vector.
Upvotes: 0