Deleting from vector in for loop crashes? - c++

I'm having a problem with my looping over a vector, and deleting values from another vector sometimes crashes my program. I have this vector of int's to keep track of which elements should be removed.
std::vector<int> trEn;
Then I loop through this vector:
struct enemyStruct {
float x, y, health, mhealth, speed, turnspeed;
double angle, tangle;
};
std::vector<enemyStruct> enemies;
The loop looks like this:
for ( unsigned int i = 0; i < bullets.size(); i++ ) {
for ( unsigned int j = 0; j < enemies.size(); j++ ) {
if ( bullets[i].x > enemies[j].x-10 && bullets[i].x < enemies[j].x+10 && bullets[i].y > enemies[j].y-10 && bullets[i].y < enemies[j].y+10 )
{
enemies[j].health-=bullets[i].dmg;
if(enemies[j].health<=0){trEn.push_back(j);break;}
}
}
}
The bullets vector is just another vector similar to the enemies vector, but with bullets in it. That one does not seem to be the problem. All this code works well, but when it comes to actually delete the items in my enemies vector the program sometimes crashes.
std::reverse( trEn.begin(), trEn.end() );
for ( unsigned int g = 0; g < trEn.size(); g++ ) {
unsigned int atmp = trEn.at(g);
if(atmp<=enemies.size()&&atmp>=0)enemies.erase(enemies.begin()+atmp,enemies.begin()+atmp+1);
} trEn.clear();
First I reverse the vector of int´s so that it will go from back to front. If i did´nt do this all values after trEn[0] would be invalid.
This is the loop which gives me a crash, but only sometimes. What I´m trying to do is a top-down shooter game, and it seems that when lots of things should be removed at the same time it just crashes. Please help me with this!
Just ask if I was unclear or if there is anything missing.

The only seemingly obvious thing would be:
if(atmp<=enemies.size() ...
Are you sure you do not mean (atmp < enemies.size()) here? Otherwise your code
enemies.erase(enemies.begin()+atmp, ...
will for sure produce some serious issues.

Your first code sample are two nested loops - you iterate over bullets and for each bullet you iterate over enemies adding enemy indices to trEn vector. What makes you think that contents of trEn are sorted in ascending order after that? For first bullet you can add index 3, and for the second index 2. You can even add same index for different bullets. Or am I missing something?

Related

What is the correct way to horizonatally concatenate std::vectors?

I have a 2D-matrix whose column size increases after every iteration but the row size remains fixed. For each iteration, a function returns a matrix which I would like to stack horizontally. Following is the code I tried but I think I am doing something wrong in the big_mat[ii].insert part. But I looked around and found codes for vertical stacking where you can start from big_mat.end() and perform insert. But I want the row size to remain fixed. Can you please help me with this ? Also the maximum final size would be of the order 1,000,000 times 5,000.
std::vector<std::vector<float> > big_mat;
big_mat.reserve(fixed_row_dim);
std::vector<std::vector<float> > small_mat;
for (some condition){
// small_mat is always fixed_row_dim x some_dim
small_mat = GetMat(params,fixed_row_dim);
for (int ii = 0; ii < fixed_row_dim; ii++){
big_mat[ii].insert(big_mat[ii].end(),small_mat[ii].begin(),small_mat[ii].end());
}
}
I have tried to compile your code, with necessary editions of course and it is working just fine. so what is the problem and what kind of error do you get?
int main() {
std::vector<std::vector<float> > big_mat;
big_mat.reserve(5);
std::vector<std::vector<float> > small_mat;
for (int i = 0; i < 10; i++){
// small_mat is always fixed_row_dim x some_dim
std::vector<float> example = { 1, 2, 3, 4, 5 };
std::vector<std::vector<float>> small_mat;
for (int ii = 0; ii < 5; ii++) {
small_mat.push_back(example);
}
for (int ii = 0; ii < 5; ii++){
big_mat[ii].insert(big_mat[ii].end(), small_mat[ii].begin(), small_mat[ii].end());
}
}
}
however I get "debug assertion failed" error while trying to run that code in visual studio 2013. the reason was that big_mat was empty- had size smaller than the number of iterations. changing the initialization of big_mat from:
big_mat.reserve(5);
to:
for (int ii = 0; ii < 5; ii++) {
big_mat.push_back(*(new std::vector<float>()));
}
fixed the issue. I think that this is the problem with your code. I will try to get some information about std::vector::reserve function and explain it to you in next few minutes.
Edit: as #Zereges pointed out. Proposed way of initialization of two dimensional vector will cause memory leaks, safe and more sexy way to achive this is:
std::vector<std::vector<float> > big_mat { 5, std::vector<float>{0f} }
Explanation: as you can read in the documentation, the reserve function
Requests that the vector capacity be at least enough to contain n elements.
just guarantee that the vector of given size will fit in the memory without reallocation required. It does not initialize anything, so your big_mat vector of vectors was empty and you have tried to iterate over it in your loops.

Inserting values to a multidimensional-vector in C++

I've got a minor problem.
I'm using multidimensional-vectors and I want to insert some values to it at a given position. I'm making a sudoku in wxWidgets and i'm getting the tiles the player have put in and wanting to store them in my mVector.
The mVector looks like this.
vector< vector<string> > board{9, vector<string>(9)};
And at first i've added values just like this.
board[row][col] = value;
"value" is a string and row/col are ints.
Is this a legit way of adding values to the mVector? I'm asking this because when I update the board, by doing this above, I for some reason can't run my other functions where i'm solving the board, giving a hint to the board and so on. Before i store the new values to it all the functions works correkt. Do I maby need to use some other type of build in functions for the vector like insert, push_back or something instead?
Since you declared the vector as size 9x9, yes that is a valid way of assigning values.
Otherwise you could declare the board as
vector<vector<string>> board;
Then fill it with
for (int i = 0; i < 9; ++i)
{
vector<string> row;
for (int j = 0; j < 9; ++j)
{
row.push_back(value); // where value is whatever you want
}
board.push_back(row);
}
But again, once the board is of size 9x9, you can simply assign a value at any cell for example
board[2][4] = "hello";
Working example

SFML 2.0 c++ sprite in array/vector

I have this in my file blocks.h:
#include <vector>
class Blocks{
public:
string files_name[4];
vector < Sprite > sprites;
void load(){
for(int i=0;i<=sizeof(files_name);i++){
Texture my_texture;
my_texture.loadFromFile(this->files_name[i]);
sprites[i].setTexture( my_texture );
}
}
Blocks(){
this->files_name[0] = "wall.png";
this->files_name[1] = "floor.png";
this->files_name[2] = "live.png";
this->files_name[3] = "coins.png";
this->load();
}
void show(int id, int X, int Y){
sprites[id].setPosition(X, Y);
window.draw(sprites[id]);
}
};
I have no errors, but my game crashed. I think, the problem is in the line which reads sprites[i].setTexture(...)
I only have the message: Process terminated with status -1073741819 (0 minutes, 2 seconds)
My IDE is Code::Blocks 10.05, and I have Windows 8.
Of course, in the file main.cpp, I have defined the window:
RenderWindow window( VideoMode(920, 640, 32 ), "Game" );
#include "blocks.h"
Blocks BLOCKS;
----UPDATE:
Ok, now it's not crashing, thanks! But, now I can't see textures! I read the post by Benjamin Lindley and I added a new vector with textures. My code looks like this now:
const int arraySize = 4;
string files_name[4];
vector < Sprite > sprites;
vector < Texture > textures;
and, in load(), I have:
for(int i = 0; i < arraySize; i++){
Texture new_texture;
new_texture.loadFromFile(this->files_name[i]);
textures.push_back(new_texture);
sprites[i].setTexture(textures[i]);
and then it crashes again!
---UPDATE: Now I have again changed my code and I don't have a crash, but my textures are white squares. My texture live.png works, but the other textures are white! Here's my new code:
Sprite new_sprite;
new_sprite.setTexture(textures[i]);
sprites.push_back(new_sprite);
The problem is this line:
for(int i=0;i<=sizeof(files_name);i++){
If you print out the value of sizeof(files_name), you will find that it is 16 instead of 4! Don't use sizeof here. Also, don't use <= here, since even if you had replaced sizeof(files_name) with 4, you would have tried to access files_name[4], which would also give you an error.
Instead you could use:
const int arraySize = 4;
string files_name[arraySize];
...
for(int i = 0; i < arraySize; i++)
or something of that sort.
Also, hopefully you initialize sprites at some point. You need to fill your vector with Sprites (with something like sprites.push_back(mySprite)) before you call load().
SFML sprites store their associated textures by pointer. The textures you are creating are local to the loop, and so are destroyed at the end of each iteration, thereby invalidating the pointer in the sprite. You need to keep your textures alive for the duration of whatever sprite uses them.
Also, your sprites vector has no elements, you need to either specify a size, or use push_back in your loop.
Also, as Scott pointed out, sizeof(files_name) is not the appropriate terminating value for your loop, since that gives you sizeof(string) * number of elements in the array. You only want the number of elements in the array.
Ok, it works only in two loop: Thanks for helping :)
vector < Sprite > sprites;
vector < Texture > tekstures;
and:
for(int i = 0; i < arraySize; i++){
Texture new_texture;
new_texture.loadFromFile(this->files_name[i]);
tekstures.push_back(new_texture);
}
for(int i = 0; i < arraySize; i++){
Sprite new_sprite;
new_sprite.setTexture(tekstures[i]);
sprites.push_back(new_sprite);
}
and in one loop it doesn't work, i have white textures:
for(int i = 0; i < arraySize; i++){
Texture new_texture;
new_texture.loadFromFile(this->files_name[i]);
tekstures.push_back(new_texture);
Sprite new_sprite;
new_sprite.setTexture(tekstures[i]);
sprites.push_back(new_sprite);
}
Greetings !

3D Array to 3D std::vector

I replaced a 3D array with a 3D std::vector in my code function and it's entering a infinite loop .Could you give me a hint,I really need to use a vector instead an array.Thanks:)
My initial code was:
//arr is a 3D array of a sudoku table,the 3 rd dimension is for keeping values 0 to 13
//for a cell, and when I assign values I start from index 1 to 12
bool sol(int arr[12][12][13]) {
int row,col;
if(!find_empty(arr,row,col)) return true;
for(int i=1;i< 12;i++) { //for digits 1 to 12
if(is_working(arr,row,col,arr[row][col][i]) ) { //if i can put the value in a cell
arr[row][col][0] = arr[row][col][i]; //replace the first element for a cell with that value
//here I want to use vector because I want to use an ac3 algorithm
//and remove those values that not satisfy constraints and shrink domain size having less values to verify with backtrack
if(sol(arr)) return true;
arr[row][col][0] = 0;
}
}
return false;//if not backtrack
}
I replace arr with:
std::vector<std::vector<std::vector<int> > > vec;
vec.resize(12);
for(int i=0;i<12;i++)
{
vec[i].resize(12);
for(int j=0;j<12;j++)
{
vec[i][j].resize(13);
for(int k=0;k<13;k++)
vec[i][j][k]=table[i][j][k];
}
}
bool sol(std::vector<std::vector<std::vector<int> > >& vec) {
int row,col;
if(!find_empty(vec,row,col)) return true;
for(int i=1;i< vec[row][col].size();i++) {//for remainig values in domain
if(is_working(vec,row,col,vec[row][col][i]) ) {//same as above but having less values to verify for
vec[row][col][0] = vec[row][col][i];
if(sol(vec)) return true;
vec[row][col][0] = 0;
}
}
return false;
}
and now it's entering a infinite loop!The initial code has no errors,it's a simple backtracking.The problem appears after I replace arr with vec.Could you give me some advice on how to replace 3D arr with an 3D vector
Your question is not clear enough. If you can also post the code for is_working and find_empty, then we would be able to see how you are getting the values of row and column.
I would have put this as a comment but being a new member and not having enough reputations, I have to put this as an answer. I'll edit it once you share the code for is_working() and find_empty()
I have solved the problem. I used a matrix of vectors instead a 3D vector and it works great :D
maybe this better for 3d one, 4x4x4
std::vector<std::vector<std::vector<double>>> matrix;
matrix.resize(4, std::vector<std::vector<double>>(4,std::vector<double(4)));

C++: Improving cache performance in a 3d array

I don't know how to optimize cache performance at a really low level, thinking about cache-line size or associativity. That's not something you can learn overnight. Considering my program will run on many different systems and architectures, I don't think it would be worth it anyway. But still, there are probably some steps I can take to reduce cache misses in general.
Here is a description of my problem:
I have a 3d array of integers, representing values at points in space, like [x][y][z]. Each dimension is the same size, so it's like a cube. From that I need to make another 3d array, where each value in this new array is a function of 7 parameters: the corresponding value in the original 3d array, plus the 6 indices that "touch" it in space. I'm not worried about the edges and corners of the cube for now.
Here is what I mean in C++ code:
void process3DArray (int input[LENGTH][LENGTH][LENGTH],
int output[LENGTH][LENGTH][LENGTH])
{
for(int i = 1; i < LENGTH-1; i++)
for (int j = 1; j < LENGTH-1; j++)
for (int k = 1; k < LENGTH-1; k++)
//The for loops start at 1 and stop before LENGTH-1
//or other-wise I'll get out-of-bounds errors
//I'm not concerned with the edges and corners of the
//3d array "cube" at the moment.
{
int value = input[i][j][k];
//I am expecting crazy cache misses here:
int posX = input[i+1] [j] [k];
int negX = input[i-1] [j] [k];
int posY = input[i] [j+1] [k];
int negY = input[i] [j-1] [k];
int posZ = input[i] [j] [k+1];
int negZ = input[i] [j] [k-1];
output [i][j][k] =
process(value, posX, negX, posY, negY, posZ, negZ);
}
}
However, it seems like if LENGTH is large enough, I'll get tons of cache misses when I'm fetching the parameters for process. Is there a cache-friendlier way to do this, or a better way to represent my data other than a 3d array?
And if you have the time to answer these extra questions, do I have to consider the value of LENGTH? Like it's different whether LENGTH is 20 vs 100 vs 10000. Also, would I have to do something else if I used something other than integers, like maybe a 64-byte struct?
# ildjarn:
Sorry, I did not think that the code that generates the arrays I am passing into process3DArray mattered. But if it does, I would like to know why.
int main() {
int data[LENGTH][LENGTH][LENGTH];
for(int i = 0; i < LENGTH; i++)
for (int j = 0; j < LENGTH; j++)
for (int k = 0; k < LENGTH; k++)
data[i][j][k] = rand() * (i + j + k);
int result[LENGTH][LENGTH][LENGTH];
process3DArray(data, result);
}
There's an answer to a similar question here: https://stackoverflow.com/a/7735362/6210 (by me!)
The main goal of optimizing a multi-dimensional array traversal is to make sure you visit the array such that you tend to reuse the cache lines accessed from the previous iteration step. For visiting each element of an array once and only once, you can do this just by visiting in memory order (as you are doing in your loop).
Since you are doing something more complicated than a simple element traversal (visiting an element plus 6 neighbors), you need to break up your traversal such that you don't access too many cache lines at once. Since the cache thrashing is dominated by traversing along j and k, you just need to modify the traversal such that you visit blocks at a time rather than rows at a time.
E.g.:
const int CACHE_LINE_STEP= 8;
void process3DArray (int input[LENGTH][LENGTH][LENGTH],
int output[LENGTH][LENGTH][LENGTH])
{
for(int i = 1; i < LENGTH-1; i++)
for (int k_start = 1, k_next= CACHE_LINE_STEP; k_start < LENGTH-1; k_start= k_next; k_next+= CACHE_LINE_STEP)
{
int k_end= min(k_next, LENGTH - 1);
for (int j = 1; j < LENGTH-1; j++)
//The for loops start at 1 and stop before LENGTH-1
//or other-wise I'll get out-of-bounds errors
//I'm not concerned with the edges and corners of the
//3d array "cube" at the moment.
{
for (int k= k_start; k<k_end; ++k)
{
int value = input[i][j][k];
//I am expecting crazy cache misses here:
int posX = input[i+1] [j] [k];
int negX = input[i-1] [j] [k];
int posY = input[i] [j+1] [k];
int negY = input[i] [j-1] [k];
int posZ = input[i] [j] [k+1];
int negZ = input[i] [j] [k-1];
output [i][j][k] =
process(value, posX, negX, posY, negY, posZ, negZ);
}
}
}
}
What this does in ensure that you don't thrash the cache by visiting the grid in a block oriented fashion (actually, more like a fat column oriented fashion bounded by the cache line size). It's not perfect as there are overlaps that cross cache lines between columns, but you can tweak it to make it better.
The most important thing you already have right. If you were using Fortran, you'd be doing it exactly wrong, but that's another story. What you have right is that you are processing in the inner loop along the direction where memory addresses are closest together. A single memory fetch (beyond the cache) will pull in multiple values, corresponding to a series of adjacent values of k. Inside your loop the cache will contain some number of values from i,j; a similar number from i+/-1, j and from i,j+/-1. So you basically have five disjoint sections of memory active. For small values of LENGTH these will only be 1 or three sections of memory. It is in the nature of how caches are built that you can have more than this many disjoint sections of memory in your active set.
I hope process() is small, and inline. Otherwise this may well be insignificant. Also, it will affect whether your code fits in the instruction cache.
Since you're interested in performance, it is almost always better to initialize five pointers (you only need one for value, posZ and negZ), and then take *(p++) inside the loop.
input[i+1] [j] [k];
is asking the compiler to generate 3 adds and two multiplies, unless you have a very good optimizer. If your compiler is particularly lazy about register allocation, you also get four memory accesses; otherwise one.
*inputIplusOneJK++
is asking for one add and a memory reference.