What exactly is an "assert", or more specifically, how do I get rid of an error. When I create a vector of pointers to a class with data member int x, and then do this:
for(I=antiviral_data.begin();I<antiviral_data.end();I++)
{
if((*I)->x>maxx)
{
antiviral_data.erase(I);
}
}
And run the program, I get no errors until x is greater than maxx and I use .erase(), at which point I get this error:
Debug Assertion Failed!
Program: ...My Documents\O.exe File:
...include\vector Line: 116
Expression:
("this->_Has_container()",0)
For information on how your program
can cause an assertion failure, see
the Visual C++ documentation on
asserts.
(Press Retry to debug the application)
[Abort][Retry][Ignore]
Also, if I try to use cout:
cout<<(*antiviral_data.begin())->x<<endl;
I get this error:
Debug Assertion Failed!
Program: ...My Documents\O.exe File:
...include\vector Line: 98
Expression: vector iterator not
deferencable
For information on how your program
can cause an assertion failure, see
the Visual C++ documentation on
asserts.
(Press Retry to debug the application)
[Abort][Retry][Ignore]
Could somebody please tell me why I can't USE any of the data in the vector, and how to fix it?
ALSO: antiviral_data is a vector of pointers, with a single element:
antiviral_data.push_back(new aX1(player.x,player.y,'>'));
If that helps.
The most probable reason why you get the assertion is that you increment I after an erase. Try this instead:
for(I=antiviral_data.begin();I!=antiviral_data.end();)
{
if((*I)->x>maxx) I=antiviral_data.erase(I); else ++I;
}
See also http://www.cppreference.com/wiki/stl/vector/erase , search for invalid iterators on that page.
An assert is typically an expression entered by a developer for debug and error control purposes - you put different "sanity checks" in your code, and have it crash the program if the check is not reached.
For example, imagine you had code that was going to divide two numbers somewhere down the road. Even though you always expect a division by non-zero, you put at assert before the division in case an argument got miscalculated. If the assert fails, it means somewhere up the road there was a failure.
Assertions typically appear only in the debug version in the code (If you use visual C++ you can compile for debug and release). While compiling in release mode would eliminate the results, it is a very bad idea, since you would still have an error and probably really bad results.
Somewhere in the implementation of Vector (is it standard), and speciifcally in line 98, there is an assert. If you have access to the vector code, look to see what the assert is or debug up to that point. This could indicate an error in the vector implementation, or in the code that calls vector.
The stuff you posted gives us some hints of what's going on, but it would be useful if you could paste more of the program, including where the vectors are defined.
The problem is with erase call. You are iterating through a container and at the same time erasing elements from it. After doing an erase, your iterator becomes invalid. If you want to remove elements of a particular value from a vector use erase with remove_if algorithm. This is known as a erase-remove idiom and explained very well in Scott Meyer's Effective STL book. You can also refer to this question Erasing elements from a vector for more information.
You already have a couple of good answers about what is an assertion and why it is being triggered in your code. Now, you may want to consider using STL algorithms for a two pass erasure.
namespace {
struct exceeds : public std::unary_function< TheUnknownType*, bool >
{
exceeds_max( int max ) : maxx( max ) {}
bool operator()( TheUnknownType* data ) {
return data->x < max;
}
private:
int maxx;
};
}
void your_function()
{
std::vector< TheUnknownType* >::iterator new_end;
new_end = std::remove_if( antiviral_data.begin(), antiviral_data.end(), exceeds(maxx) );
antiviral_data.remove( new_end, antiviral_data.end() );
}
The main advantage is that erasing elements in a vector is an expensive operation. For each element erased, all elements from that position to the end of the vector must be moved one position towards the beginning. The second element you erase will force a second move of all the elements from there on... The STL remove_if algorithm performs the moves only once to their final position returning an iterator one past the last element not removed element. Then you can perform one single std::vector<>::remove that will not need to relocate elements.
Related
First off, good morning/day/evening and thank you to whoever is taking their time to read this.
The Setup:
In my code I have two different classes: ColObj and QuadNode (that is, the 'collision object' and a node in a quad tree used to check for proximity of objects. I know there are probably libraries out there for this, but I need to write my own system, so they would be of no use here). Things work like this: When a ColObj object is created, it is added into an appropriate QuadNode (the node has a std::list of pointers to ColObj), so that the node can inform it when it collides with something; the ColObj object also receives a pointer to the node that's holding it and a list iterator to the list iterator containing its address so when it's out of the node's bounds or gets destroyed it can 'leave' it, and clean up the node, that is, remove and reference to itself from the node. I made it like this because in a lot of cases it's going to be a frequent operation and I want it to be in constant time.
The Code:
This is the method used to 'attach' a ColObj to a QuadNode. I suspect the problem is not in here.
void QuadNode::obj_add(ColObj *obj) {
std::cout<<"QuadNode at depth ("<<depth<<") received new ColObj.\n";
objects.push_back(obj);
obj->holder = this;
obj->my_iter = std::prev( objects.end() );
if ((int)objects.size() > MAX_OBJECTS && depth < MAX_DEPTH) split();
}
This is the QuadNode method that a ColObj uses to clean up the node. Here is where the problem occures for some reason.
void QuadNode::obj_list_erase(std::list<ColObj*>::iterator iter) {
std::list<ColObj*>::iterator iter2 = objects.begin();
objects.erase(iter);
}
The first line in this method is simply to provide additional information for debugging and will be removed afterwards.
The Error:
The strangest part is that, for the most part, the code works fine. Then at one point, randomly, it throws an assertion failure, saying that a "list iterator is not incrementable". That's the first strange thing, I'm not trying to increment it anywhere in my code (though I know that std::list::erase returns the following iterator, but I never attempt this operation on an invalid or "past-the-last" iterator).
Anyway, Visual Studio offers to fire up the debugger and put a break point in the code, so naturally I agree. So here's the weirdest part:
Local and auto variables, debugger screenshot
(I can't embed an image since I'm new here, so it is what it is).
So, unless I'm gravely mistaken here, it's telling me that the passed iterator is equal to be beginning iterator of the list, that its element is still present in the list and corresponds to the first (or rather zero-th) element of the list. And yet, the erase() method fails.
For what it's worth, I've noticed that every single time the program breaks, the passed iterator points to the zero-th element of the list, though I can confirm that the method usually works even when there's only one element in the list.
Additional info and conclusion:
I'm not manually incrementing the iterator anywhere else in the code (which is pretty small and simple anyway).
The IDE I'm using is Visual Studio Community 2015, but I don't know the compiler version. (Microsoft and their naming schemes...)
I tried finding another thread about this on SO but every one I checked was about wrongly placed i++ in list iterations, so sorry if this is a duplicate thread.
I'm completely confused by this problem, because usually between the excellent debugger, std::cout and browsing SO I somehow fix the issue, but this time around nothing useful is coming up, so any advice or suggestion would be very welcome.
Edit:
One thing I have tried "just 'cause" editing the QuadNode::obj_list_erase method so that it compares the passed iterator with the first iterator of its list (objects.begin()) and if they're equal use objects.pop() to remove it, else erase it normally. It didn't work, saying that the iterators weren't compatible, whatever that means...
After finding out that I cannot even compare the passed iterator with any other iterator from the list that was supposed to be holding it (I was getting Assertion failure: iterators not compatible), I searched SO for more info on what it means, and... Andrew Kashpur was right. I did manage to invalidate an iterator by removing the pointed element from the list and putting it back immediately, but without updating the iterator.
Moral of the story: An iterator can seem to point to a "correct" memory location, it may even point to the same address as some valid iterator does, but that does not make it valid or compatible.
I'm working on implementing a divide-and-conquer algorithm that finds the two points closest to eachother and the distance between them. My final solution finds the correct answer (compared to using brute force), but about 1/3 of the time would return a segmentation fault error. I've been working on fixing this issue for a couple of days now, adding print statements here and there, but couldn't find the issue. I would appreciate it if someone took a look at my code.
Your "divide" loop assumes that X and Y have the same number of elements. If Y has fewer than X you'll run into undefined behavior, which could be funny results or a crash.
Try changing your access method for the vectors. Vector subscript-operator does seem to have an eratic behaviour in some compilers/platforms (at least from my perspective). I think the problem comes from it being a linked list, resulting in being non-contiguous in memory, but that's just a guess. (EDIT: std::vector are contiguous in memory, the problem is something else) Try using iterators instead (easy-peasy with auto keyword), such as:
for (auto iter = Yprime.begin(); iter != Yprime.end(); iter++) {
// Your code here
}
Hope this works for your case!
I'm coding a program where I want to draw a card, and then delete so that it doesn't get drawn again.
I have a vector of Cards (class containing 2 structs that define Suit and Value) called deck and I don't really know how to use iterators very well, here a code snippet:
void Player::discardCard(CardDeck masterDeck)
{
cout << "Erasing: " << masterDeck.getDeck().at(cardSelect).toString() << endl;
/*Attempt1*/
masterDeck.getDeck().erase(masterDeck.getDeck().begin()+cardSelect);
/*Attempt 2*/
vector<Card>::iterator itr;
itr = masterDeck.getDeck().begin() + cardSelect;
masterDeck.getDeck().erase(itr);
}
cardSelect has the location of the card I'm going to delete.
It's generated randomly within the boundaries of 0 and the size of deck; therefore it shouldn't be pointing to a position out of boundaries.
Everytime I compile I get the following error:
"Expression: vector erase iterator outside range"
I really don't know what to do, hopefully someonw can help me, thanks in advance!
My bet is that getDeck returns the vector by value. It causes itr to point to and erase to operate on different copies of the vector. Thus you get the error. You should return the vector by reference. Change getDeck signature to this one:
vector<Card>& getDeck()
Let me go off topic first. Your design is a little suspect. First passing in CardDeck by value is almost certainly not what you want but that's even beside the point. Why should your Player class have all this inside knowledge about the private innards of CardDeck. It shouldn't care that you store the deck as a vector or deque (ha ha), or what the structure is. It just shouldn't know that. All it knows is it wants to discard a card.
masterDeck.Discard(selectedCard);
Also note that selectedCard has to be between 0 and ONE LESS than the size of the deck, but even that's probably not your problem (although it will be 1/53rd of the time)
So to answer your question we really would need to now a little more about masterDeck. Did you implement a valid custom copy constructor? Since you're passing by value odds are good you're not correctly copying the underlying vector, in fact it's probably empty and none of the deletes will work. Try checking the size. If you don't ever want the deck copied then you can let the compiler help you by declaring a private copy constructor and then never defining it. See Scott Meyer's Effective C++ Item 11.
Finally one last piece of advice, I believe once you erase with your iterator, you invalidate it. The vector might get reallocated (almost certainly will if you erase anywhere but the end). I'm just telling you so that you don't try to call erase more than once on the same iterator. One of the tricky things about iterators is how easy it can be to invalidate them, which is why you often seen checks for iter != coll.end().
"It's generated randomly within the boundaries of 0 and the size of deck".
The valid range should be "between 0 and the size of the deck minus 1". This could generate range error at run time.
I hit a wall while debuging my C++ class. It's a graph of sorts, something like this:
class Graph {
class Node {
std::map<int, Node>::iterator _neighbors[4];
};
std::map<int, Node> _map;
};
Basically, each node keeps track of exactly 4 neighbors by storing iterators to them in the containing class' map.
The problem is that when I go to display the contents of _map in VS2008 during debugging, I get something like this:
- _map
- [0]
first
- second
- _neighbors
- _ptr
first
- second
- _neighbors
- _ptr
first
- second
- _neighbors
...
Apparently, instead of listing the 4 neighbors of the Node with index 0 in the map, it lists its first neighbor, then the first neighbor's first neighbor, then its first neighbor and so on ad infinity. Also, at no point does _neighbors appear as an array, even though it is declared as such.
I found an add-on called VSEDebug that supposedly has enhanced STL display, but it's for VS2k3 and I couldn't get it to work in 2k8 (neither the binaries, nor compiling it myself).
The immediate window isn't much help either, as trying to call _map.operator[] returns with CXX0058: Error: overloaded operator not found.
Any ideas how I can get a meaningful display of the contents of my map? Note that I'm fairly new to VS as a whole, so I'll probably need detailed instructions. :)
You can type the name of the symbol in the command window - immediate window and start following its member pointers. For example, if you debug a std::vector named v and want to access its element at position 2, type
*(v._Myfirst + 2)
Of course, the member _Myfirst depends on the implementation. But I think you get the idea. (visual studio has some problemas resolvindo overloads of the operators)
You can try your hand at writing a custom visualizer if you like, however you might end up duplicating functionality that already exists somewhat. Here's an article that goes over the basics:
http://www.virtualdub.org/blog/pivot/entry.php?id=120
If you just want to view all your array elements you can type "_map[0].second._neighbors,4" in the quick watch window to view it as an array of four, but this isn't exactly the fastest thing in the world.
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.
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.
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.
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.
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.
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.
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.
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: 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.