Invalid pointer operation error when calling vector.erase() function - c++

I am using vector::erase() function to delete the the first element in the vector until it is empty but my compiler is giving me an "Invalid Pointer Operation" error.
I have a vector of class-defined objects, foo, called bar.
I am deleting elements one by one like so:
for(int i = 0; i < bar.size(); i++){
if(!bar.empty()){
bar.erase(bar.begin());
}
}
When I run my program, it only completes one iteration (no matter the size) and breaks on the second.
Specifically, it breaks on the STL function _Destroy
template<class _TyDtor> inline
void _Destroy(_TyDtor _FARQ *_Ptr)
{ // destroy object at _Ptr
_DESTRUCTOR(_TyDtor, _Ptr);
}
*note I know there is a clear function that would do this more neatly but this is just a simplified example of something else that I am trying to do

As always when modifying a range while traversing the range, you cannot unconditionally increment the loop counter.
Consider the simple example of a two-element set. When i is 0, you remove the first element and increment i. Now i is 1 and bar.size() is 1, and the loop exits, failing to delete the second element.
The standard solution is to make the increment conditional on not modifying the container:
for (int i = 0; i < bar.size(); /* no increment here */) {
if (!bar.empty()) {
bar.erase(bar.begin());
} else {
++i;
}
}
When you do modify the container by erasing an element, i stays constant but the range moves one element closer to it. Also incrementing i would be double-counting.
(This is an extremely common mistake, though usually it's expressed in terms of iterators, e.g. here or here or here.)

The problem is the condition part of the loop bar.size() which keeps changing in each iteration i.e., decreasing in this example by 1.
It is difficult to say what exactly you are trying to achieve within the loop but if you want to execute the loop bar-size () times then use the follow logic:
const size_t vecSize = bar.size ()
for(int i = 0; i < vecSize ; i++)
{ ..... }
Otherwise if you want to execute the loop till bar-size () is empty, then use the while loop as follows:
while (bar.size > 0)
{ ..... }

Related

C++: Is it safe to change value of iterator of a while loop?

#include <iostream>
using namespace std;
int main() {
int x = 10;
while (x>0) {
x = x-1;
cout << x << "\n";
}
return 0;
}
In this simple program, I change value of iterator of a while loop. But is it safe to do that? Will the program run into segmentation fault sometimes?
How about this pseudo code:
vector <vector<Struct> > all_vectors;
vector<Struct> old_vector, new_vector;
Initialize old_vector;
all_vectors.push_back(old_vector);
index = 0;
while (all_vectors[index].size()>0) {
calculate new_vector;
if (new_vector not empty) all_vectors.push_back(new_vector);
index += 1;
}
My real code is a bit messy and lengthy so I only posted the main idea of my real code. But for this case, I run into segmentation fault. When I try to debug, the problem seems to be with the line: index += 1.
I cannot understand why. I am sorry if my code is not readable, I am just learning C++.
I'm guessing now, but if your loop look something like the second example you provide, the segmentation fault could be caused by the check in the while statement.
...
index = 0;
while (all_vectors[index].size() > 0) {
^-- This, this could be the problem
...
index += 1;
}
The reason being that the program tries to access a vector that is out of range.
This would probably fix the problem
...
while (index < all_vectors.size() && all_vectors[index].size() > 0) {
^---- Check this index first ^---- only checked if first condition is true
...
And by the look of it, i would recommend using a for loop instead:
...
for (size_t index = 0; index < all_vectors.size() && all_vectors[index].size() > 0; ++i) {
...
I could also recommend when having segmentation fault with vectors to use .at() instead of operator[] because that does a range check, and can help you find the problem faster.
You want to ask whether changing the value of the loop variable (x) is safe or not. Remember, an iterator is an object (like a pointer) that points to an element inside the container so the integer variable int x is not an iterator.
Now, the answer to your question would be that it is totally safe to change the value of the loop variable inside the loop body. You cannot expect the loop to terminate if you are not changing the value of the loop variable!
Coming to the second part, changing the value illogically would result to an infinite loop or a segmentation fault. Suppose, you have written x=x+1 instead of x=x-1 inside the loop body, the value of x will always be more than 0 in this case and hence the loop will never terminate.
It is inherently necessary to change the value of an input iterator in order to advance (in typical cases). If you don't change the iterator that is used as the end condition, then you will never reach the end of the interations unless the iteration starts at the end - i.e. there are zero iterations.
Note that iterator is different concept from a loop variable, but the answer applies equally to loop variables as well.

Is there a way to repeatedly insert an element at a specific position to a std::vector?

I know my question seems very similar to this one, but the solutions provided there don't work in this case.
What I'm trying to do is very simple, put an element to a specific position in a vector.
#include <vector>
int main()
{
std::vector<int> vec;
vec.reserve(2);
vec.insert(vec.begin() + 0, 0);
vec.insert(vec.begin() + 0, 1);
for (size_t i = 0; i < vec.size(); i++)
{
std::cout << vec.at(i) << "\n";
}
}
The output is
1
0
But I want the output to be just 1.
The second time I insert, the element is inserted at the 0th position and the element previously at 0th moves to 1st position. I want the second call to insert have the same exact effect as the first call i.e. insert element to 0th position. In other words, I want the second call of insert to substitute the value at 0th position. How do I do this?
CLARIFICATION:
My code included in this question is a short example of what I want. I'm calling insert twice but the first argument to insert is the same in both calls, so I don't understand why the second call to insert changes the size.
In my actual code, the insert call is protected by mutex and is called by a std::thread, the thread might call the insert function multiple times for the same position (first argument to insert), so I want to find a way to not increase the vector size and simply replace the value at the specified position.
You're confusing two separate operations. Insertion of an element, and assignment to an element. Insertion creates a new element in the vector, increasing its size. Assignment changes the value of an element that's already there. Both of your calls to insert are in fact doing the same thing. They are inserting an element to the front position of your vector, and shifting all existing elements down by 1.
What you seem to be asking for is an operation that assigns to an element at a given index, but first inserts that element if it doesn't already exist. std::vector has no such operation, but you can write a function which allows you to do that.
template<typename T, typename A>
T& getElement(std::vector<T, A>& v, size_t N) {
if (N >= v.size())
v.resize(N + 1);
return v[N];
}
// usage
getElement(vec, 4) = 7;
This has the side effect of inserting default constructed elements in any positions preceding that index which don't yet exist in the vector, which doesn't seem very desirable to me. Maybe you should consider using a std::map or std::unordered_map instead. They have the exact behavior you are describing, but without inserting extra elements.
std::map<int, int> m;
m[0] = 0;
m[0] = 0;

custom sorting function with struct

So, I have a problem with this sorting function, that I wrote to sort struct.
My initial thought was to have a while cycle until there is no changes happening, and inside have for cycle that goes through an array[10], comparing two elements that are next to each other. If next element is larger than previous one, they are exchanged, and iterator thrown back to zero.
Everything kind of works, except for the first element, which is not highest. From second to last, everything is fine.
Any pointers, to where I have made a mistake? Code seems fine to me...
I know I could have used <algorithm>, but I am supposed to write my own function for this.
void izvadaPecRez(Pari masivs[])
{
Pari temp;
bool change;
int i;
while(change!=false)
{
for(i=0;i<10;i++)
{
if(masivs[i+1].kopejais>masivs[i].kopejais)
{
temp=masivs[i];
masivs[i]=masivs[i+1];
masivs[i+1]=temp;
change=true;
i=0;
}
else
{
change=false;
}
}
}
for(i=0;i<10;i++)
printone(masivs, i);
}
i=0 is going to happen right before the increment in the for loop runs, so the effect of the statement will be that i==1 in the next loop. The easiest way to get your intended behavior is to just break from the for-loop after you swap the elements (don't worry, it'll only break the for-loop, not the while-loop). You should also just set change=false at the top of the while-loop, rather than setting it whenever you don't swap elements.
Use this code instead for sorting (still untested):
#include<array>
#include<functional>
#include<algorithm>
std::array<Pari,100> masivs;
auto compare=[](const Pari& a, const Pari& b) {return a.kopejais<b.kopejais;};
std::sort(masivs.begin(), masivs.end(), compare);
Here, instead of a normal array, std::array is used. Next, a custom comparison lambda-function is defined and passed to std::sort.
I don't know whether it does exactly the same as your code, but at least will sort your classes according to the entry kopejais.
EDIT: Here is a version of your code which should work faster than the one in the accepted answer:
void izvadaPecRez(Pari masivs[])
{
bool change=true;
while(change==true)
{
change=false;
for(int i=0;i<10;i++)
{
if(masivs[i+1].kopejais > masivs[i].kopejais)
{
std::swap(masivs[i], masivs[i+1]);
change=true;
}
}
};
for(i=0;i<10;i++)
printone(masivs, i);
}
The reason is that you are not repeatedly looping over already ordered parts of the array, which is done by using break after the swap.

vector::empty() bugged, or am I missing something?

I've got this piece of code, which throws an out-of-range error.
if (!_enemyVec.empty())
{
for (std::vector<EnemyShip*>::size_type i = 0; i != _enemyVec.size(); i++)
{
if (!_projVec.empty())
{
for (std::vector<Projectile*>::size_type y = 0; y != _projVec.size(); y++)
{
===>_projVec[y]->CheckCollision(_enemyVec[i]);
if (_projVec[y]->Destroy())
DestroyProj(y);
if (_enemyVec[i]->Destroy())
DestroyShip(i);
}
}
}
}
Notice how I've got if (!_projVec.empty()) which should be "false" if the vector _projVec is empty.
The "===>" is where I get my out-of-range error(since _projVec is empty).
According to http://www.cplusplus.com/reference/vector/vector/empty/ vector::empty "Returns whether the vector is empty (i.e. whether its size is 0)."
However when I run the code it goes into the 2nd for-loop throwing an out-of-range error, while my vector is empty (it's size is 0)?
+ _projVec { size=0 } std::vector<Projectile *,std::allocator<Projectile *> >
I think I'm missing something so I'm wondering if anyone here can clear this up?
EDIT: Here are my DestroyProj/Ship functions.
void ObjectManager::DestroyShip(std::vector<EnemyShip*>::size_type &index)
{
delete _enemyVec[index];
_enemyVec[index] = nullptr;
_enemyVec.erase(_enemyVec.begin() + index);
index--;
AddScore(10);
}
void ObjectManager::DestroyProj(std::vector<Projectile*>::size_type &index)
{
delete _projVec[index];
_projVec[index] = nullptr;
_projVec.erase(_projVec.begin() + index);
index--;
}
As BWG pointed out, it shouldn't iterate if they are empty from the beginning, so the problem probably lies where I set the index back once. I also realise that this is probably a bad way to iterate through the vectors, so if someone can suggest me a different way to do it would be very much appreciated.
Please note that during this nested for-loop I want to be able to remove an item from both vectors.
You have two nested loops modifying two vectors. While erasing from the inner vector is fine, erasing an element from the outer vector, is not (assume the outer has one element, only)
Probably DestroyProj() (or one of the other functions) modifies _projVec. So even if it wasn't empty at the start of the loop, it might become empty when projects are removed.
You should iterate over a copy of the vectors, or you should remember which indexes to remove and then remove them at the end. Don't let DestroyProj and DestroyShip modify the vector.

Vector erase function in for loop is not erasing vector of classes properly

I have a simple for loop:
for (int i = 0; i < c.numparticles; i++)
{
if ( labs((noncollision[i].getypos())) > 5000 )
{
noncollision.erase (noncollision.begin()+i);
}
}
Where noncollision is a vector of class particle. In this specific example, any noncollision which has a ypos greater than 5000 should be erased. I have been working with a noncollision size of 6, of which 2 have ypos much greater than 5000. However, this for loop is only erasing one of them, completely ignoring the other. My suspicion is that because noncollision is a vector of classes, that this classes is somehow protected, or causes the array function to act differently? Here is my declaration for noncollision, and for particle:
vector<particle> noncollision;
class particle{
private:
int xpos;
int ypos;
int xvel;
int yvel;
bool jc; // Has the particle just collided?
public:
etc....
};
Could anyone explain why this is happening, and how to rectify it? Do I somehow need to set up an 'erase function' for the particle class?
If you have two candidate elements next to each other (say, at i=5 and i=6), then you jump over the second, because you just erased the one at i=5... then the second becomes the new i=5 but you increment i to get i=6 on the next loop.
You need to fix your loop to properly support the fact that you're simultaneously removing elements from the same container over which you're iterating.
Typically you'd use actual iterators (rather than a counter i), and vector::erase conveniently returns a new iterator for you to use in the next iteration:
vector<particle>::iterator it = noncollision.begin(), end = noncollision.end();
for ( ; it != end; ) { // NB. no `++it` here!
if (labs(it->getypos()) > 5000) {
// erase this element, and get an iterator to the new next one
it = noncollision.erase(it);
// the end's moved, too!
end = noncollision.end();
}
else {
// otherwise, and only otherwise, continue iterating as normal
it++;
}
}
However, quoting Joe Z:
Also, since erase can be O(N) in the size of a vector, you might (a) benchmark the loop using reverse iterators too, (b) consider copying the not-erased elements into a fresh vector as opposed to deleting elements out of the middle, or (c) using a list<> instead of a vector<> if deleting from the middle is a common operation.
Or, if you're lazy, you could also just reverse your iteration order, which preserves the sanctity of your counter i in this specific case:
for (int i = c.numparticles-1; i >= 0; i--) {
if (labs(noncollision[i].getypos()) > 5000) {
noncollision.erase(noncollision.begin()+i);
}
}
Just be careful never to change i to an unsigned variable (and your compiler is probably warning you to do just that — i.e. to use size_t instead — if c.numparticles has a sensible type) because if you do, your loop will never end!
However, this for loop is only erasing one of them, completely ignoring the other.
This is because you are going front to back. When your code erases an item at, say, index 6, the item that was previously at index 7 is at the index 6 now. However, the loop is going to skip index 6 after i++, thinking that it has already processed it.
If you go back-to-front, the problem will be fixed:
for (int i = c.numparticles-1; i >= 0; i--)
{
if ( labs((noncollision[i].getypos())) > 5000 )
{
noncollision.erase (noncollision.begin()+i);
}
}
It looks like you're suffering from "Invalidated Iterator" syndrome, although in this case it's the index that's the problem.
Are the 2 elements you want to erase next to each other?
The problem is that erasing an element from a vector causes the remaining underlying elements to be copied to a new location (unless you erase the last element), and the number of elements in the vector is reduced by one.
Since you're using indexing into the vector, you're not falling foul of the first problem (which is iterators being invalidated), but:
you will never check the element immediately after the one you just erased
your indexing will spill off the end of the vector (undefined behaviour)
Modifying any sequence you're inspecting in the same loop is a bad idea. Have a look at
remove_if for a better way. This algo puts all the matching elements at the end of the vector, and returns you an iterator to the first one that was moved, allowing you to remove them all in one go safely.