views:

1088

answers:

4

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.

+7  A: 

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.

Uri
+8  A: 

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.

pts
Umm... this is just as broken. As soon as you call erase(), the iteration sequence is invalid so any iterator instance that was obtained before modifying the container is invalid. There are a bunch of ways that removing elements can be done but doing it in a for loop like this is one of those things that you shouldn't do.
D.Shawley
@D.Shawley: That isn't exactly true. Yes, iterators from before the erase operation are invalid after, but the iterator returned by erase is valid.
Zan Lynx
Damn... good point. I didn't notice the assignment. Thanks Zan.
D.Shawley
+1  A: 

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.

Naveen
A: 

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.

David Rodríguez - dribeas