tags:

views:

1372

answers:

8

I want to insert a pair< string, vector<float> > into a map, first it works, but after several loops, it cannot insert any more and throw me a segmentation fault. Can anybody give a possible reason?

Btw: I first read a file and generate the map (about 200,000 elements) and I read another file and update the old map. the error occurs while the updating step.

Can anybody help me with the info I gave above? Thanks a lot

The code is pretty long.....I just erase the previous key and then insert a new one, it seems not complicated.....but drives me crazy....could you guess what happened here?

Thanks A lot for all your answers! And I found it is really a good place for solving problems. Thanks again, I'll try to simplify my codes and add it here today or tomorrow.

Update: I used the code from MSN and it works, thanks a lot that you solved my problem without seeing my code......also many thanks to other kind-hearted people here! However, i can only choose one as the answer.

+2  A: 

Without more information, it's not easy to say, but what are you inserting? Could it simply be that you run out of memory? Although, I do think normal C++ would throw an exception in that case, are you using any custom allocators, malloc, or arrays on the stack which are overrun perhaps?

Perhaps a snippet of code describing what you do could be helpful in determining the cause of your problem.

roe
+1  A: 

It easily happens if you either modify the keys of the elements already in the data structure or if you have a bad compare function, which misleads the search algorithm.

If you can detect which concrete insert operation causes the seg.fault, then try debugging/logging with what values the compare function is called.

Alternatively, you should print the contents of the map before the erroneous insert, the keys will probably not be in order.

jmihalicza
+5  A: 

Are you inserting using the iterator you called erase() on? Or using that iterator in any way? After erase(p) is called, p is invalidated.

Arkadiy
+2  A: 

could you guess what happened here?

You're abusing memory in some way.

There are a lot of ways to do that, in C++!

Rather than guess, and without reading your code, I suggest run the kind of platform-specific debugger which will detect this problem, for example valgrind.

Your alternative is to make the problem smaller: reproduce the problem in only a few lines of code, which you can then post for people to look at.

ChrisW
+1  A: 

The type in question is pair<string, vector<float> >. You will be copying that pair on every insert. If either the string or the vector are big then you could be running out of memory.

Edit: to fix running out of memory, you can change how you insert key-value pairs to:

pair<map::iterator, bool> insert_result= map.insert(make_pair(name, vector<float>());
if (insert.second) { insert_result.first->second.swap(vector_read_in); }

That will ensure that you do not copy memory, only move it.

MSN
I might be mistaken, but wouldn't standard C++ stuff (i.e. std::string in this case) throw exceptions while when allocating memory for copying, rather than result in a segmentation fault?
roe
It depends on the compiler and the compiler settings. Some just happily return NULL.
MSN
A: 

please post some code, you cant expect us to debug your problem on guess work alone.

...but ill give it a stab anyway :) Also what compiler, and system are you doing this on?

If you are reading the data in a loop you may run out of stack space which would cause a seg fault.

Ill edit my answer if you post some code.

QAZ
A: 

Remember that if you are looping through the map, finding stuff to delete, save off the key for later deletion. If you delete while iterating, you run the risk of invalidating the iteration loop.

std::map<string, vector<float> >::iterator iter = my_map.begin();
while (iter != my_map.end()) {
  if (somethingBadAboutItem(iter)) {
    my_map.erase(iter);   // this can mess up my_map iteration above 
                          // and cause bad data access later
  }
  ++iter;
}

instead, try

std::map<string, vector<float> >::iterator iter = my_map.begin();
std::vector<string> keys_to_delete;
while (iter != my_map.end()) {
  if (somethingBadAboutItem(iter)) {
    keys_to_delete.push_back(iter->first);
  }
  ++iter;
}

for (std::size_t i = 0; i < keys_to_delete.size(); ++i) {
  iter = my_map.find(keys_to_delete[i]);
  my_map.erase(iter);
}

I am interested if other people have found something more elegant than this, but this is my preferred technique.

Bill Perkins
A: 

Bill: Have you tried something like this:

for(std::map<string, vector<float> >::iterator iter = my_map.begin(); iter != my_map.end();) {
    if(somethingBadAboutItem(iter)) {
        my_map.erase(iter++);
    } else {
        ++iter;
    }
}

The key is to postincrement the iterator when deleting, so it's still valid when incremented but you erase (and hence invalidate) a copy pointing to the previous item.

I'm not sure this technique necessarily works for all STL containers; I can't remember all the invalidation rules offhand (seems unlikely to work for vector for example, but you're normally better off using remove_if for those for non-trivial sizes) but it should be fine for map.

Peter