I have a little problem when using lists.
What I have: I am reading lines from a chatbox where new lines of text come now and then. I always fetch the last 20 lines from the box, then i want to compare them to all the lines i have fetched before. If a new line is discovered it is sent to an external function which disassembles the line for further processing. Before I used arrays and vectors, but list seem to be the better way of doing it.
My Idea: I have one list called usedlines which contains all the old allready used lines. The list fetchedLines containes the newest 20lines fetched from the chatbox.
No I simply want to loop trough both of them to find out if fetched lines containes a new line not seen before. After the loop the remains in fetchedlines are handled over to the next function.
Problem: When I loop throug this loop i get a badpointer after a while. Why? Bonus: Does anyone have a better idea to solve this 开发者_如何学编程task?
typedef list<string> LISTSTR;
LISTSTR::iterator f;
LISTSTR::iterator u;
LISTSTR fetchedlines;
LISTSTR usedLines;
fetchedlines.insert(fetchedlines.end(), "one");
fetchedlines.push_back("two");
fetchedlines.push_back("three");
fetchedlines.push_back("four");
fetchedlines.push_back("three");
usedLines.push_back("three");
usedLines.push_back("blää");
usedLines.push_back("lumpi");
usedLines.push_back("four");
for (u = usedLines.begin(); u != usedLines.end(); u++)
{
for (f = fetchedlines.begin(); f != fetchedlines.end(); f++)
{
if(*u==*f)
fetchedlines.remove(*f);
}
}
The call to fetchedlines.remove(*f)
is invalidating your iterator.
EDIT:
A possible solution to the problem you are having is to instead just iterate usedLines
and remove all elements in fetchedlines
that are contained.
for (u = usedLines.begin() u != usedLines.end(); u++)
fetchedLines.remove(*u);
//Process all of fetchedLines
The reason you are getting an error is that fetchedlines.remove (*f) modifies fetchedlines, and if it was the last element, then the for loop increments too far
Try something like this:
for (u = userLines.begin (); u != usedLines.end (); ++u)
{
for (f = fetchedlines.begin (); f != fetchedlines.end ();)
{
if (*u == *f)
{
f = fetchedlines.erase (f);
}
else
{
++f;
}
}
}
(that's of course not addressing whether this is a good way to solve the problem)
You must never modify a list (or pretty much any other container) while iterating over it. That's your immediate problem.
A more interesting problem is why you're doing it like this in the first place. Isn't there a way to get sequential numbers on the lines, or maybe timestamps, so you could just compare those?
You are removing an element from fetchedlines
while your are iterating on it.
This is why you get a bad pointer.
Because *f is an iterator pointing to an element you have just erased.
Try the following:
if(*u==*f)
{
LISTSTR::iterator t = f;;
f--;
fetchedlines.remove(*t);
}
As an aside remove searches through the list for something that matches the data pointed to by the iterator f. If you want to simple get rid of the data pointed to you are better off doing
f = fetchedlines.erase( f );
f--;
This can be done with list::remove_if
and a lambda expression. This method is still two nested loops but they are hidden inside the function calls. This may be fast enough for small lists but won't scale very well. It could be much faster if the data were sorted or if you used an ordered container.
fetchedLines.remove_if([&](std::string &str)
{
return std::find(usedLines.begin(), usedLines.end(), str) != usedLines.end();
});
精彩评论