Uberswe
Uberswe

Reputation: 1058

c++ and xcode - calling objects function throws EXC_BAD_ACCESS

This code works fine in VS2010 but now I am trying to port it to my mac with xcode 4.6 and it's giving me some bad access errors at run time. Basically I have a board class which contains a 2d array of tiles, when I create the board I can access the tiles functions but when I later run my draw function it gives me bad access. Here is a sample of my board class.

Board.h

#include "Tile.h"
class Board
{
private:
    //This is the GameBoard of a 2D array of Tiles
    Tile *** GameBoard;
    void CreateBoard(const int size);
void FillValues();
    ...
public:
Board(int size);
void DrawBoard();
    ...
}

Board.cpp

Board::Board(const int size)
{
won=false;
lost=false;
BoardSize =size;
GameBoard = new Tile**[size];
CreateBoard(size);
}

void Board::CreateBoard(const int size)
{
    ...
    FillValues()
}

void Board::FillValues()
{
    for(int x=1;x<BoardSize+1;x++)
    {
        for(int y =1;y<BoardSize+1;y++)
        {
            if (GameBoard[x][y]->Type()=="NumberTile")
            {
                                int neighbors = CountNeighbours(x,y);
                GameBoard[x][y]->SetValue(neighbors);
                                //This works
            }
        }
    }
}

void Board::DrawBoard()
{
for(int i=0;i<=BoardSize+1;i++)
{
    for (int j=0;j<=BoardSize+1;j++)
    {
        if (GameBoard[i][j]->Type() != "BorderTile") {
            GameBoard[i][j]->Draw();
            //This does not work, i get the error when it tries to use ->Type()
        }
    }
}
}

...

I call the functions like this

GI = new Board(SCREEN_SIZE);
GI->DrawBoard();

Upvotes: 1

Views: 617

Answers (1)

Joseph Mansfield
Joseph Mansfield

Reputation: 110718

GameBoard = new Tile**[size];

This just creates an array of Tile**. You don't yet have any actual Tiles or even Tile*s and later, when you're trying to access elements of the array with GameBoard[x][y]->, you're hitting undefined behaviour.

As you have it, you would need to do this:

GameBoard = new Tile**[size];      // Allocate an array of Tile**
for (int i = 0; i < size; i++) {
  GameBoard[i] = new Tile*[size];  // Allocate an array of Tile*
  for (int j = 0; i < size; j++) {
     GameBoard[i][j] = new Tile(); // Allocate an array of Tile
  }
}

However, this is awful. It's three lots of dynamic allocation that you have to remember to tidy up at the end (and tidy up correctly).

A simpler approach would be to just have an 2D array of tiles:

Tile GameBoard[CONSTEXPR_SIZE][CONSTEXPR_SIZE];

Or better yet, use the std::array container:

std::array<std::array<Tile, CONSTEXPR_SIZE>, CONSTEXPR_SIZE> GameBoard;

Here, the size given has to be a constant expression. If you need it to be dynamically sized, use a std::vector instead.


In the comments below, you say the size of your array is actually BoardSize+1. Still, you are iterating over too many elements in both your outer and inner for loops:

for(int i=0;i<=BoardSize+1;i++)

This should be:

for(int i=0; i<BoardSize+1; i++)

Also in the comments below, you say that Type returns a char*. That means you can't do your string comparison like this:

GameBoard[i][j]->Type() != "BorderTile"

This simply performs pointer comparison, since the left operand is a char* and the right operand is convertible to const char*. It doesn't compare the strings themselves. Instead, you want:

GameBoard[i][j]->Type() != std::string("BorderTile")

This will force std::string comparison to be used.

Upvotes: 3

Related Questions