1
\$\begingroup\$

c++ Beginner here, coming from Java background, and I'm getting the feeling this is a c++ specific error I'm running into. I am trying to procedurally generate a 2D map, which is of type Tile[y][x]. As seen in code below I loop through all the indeces in the 2D array and I generate a colorvalue, which lets it decide what color the tile is, and a position, which defines the position the tile should be drawn to. However, I get a read access violation when I try to add Tiles to the 2D array. What am I doing wrong here?

Also whenever I have an array that is a bit bigger than this one, I get a stack overflow error. Now I read that arrays are kept in stack memory, and the stack is only very small, so what would be a solution to this? Thanks in advance

Map.cpp:

    #include "Map.h"
    #include <memory>


    Map::Map(int size)
    {
        this->size = 10;
        noiseGenerator.SetNoiseType(FastNoise::NoiseType::Perlin);
        std::cout << "Setting noise" << std::endl;
        for (int x = 0; x < size; x++) {
            for (int y = 0; y < size; y++) {
                tileMap[x][y] = Tile{ sf::Vector2f{x * 8.0f, y * 8.0f }, noiseGenerator.GetValue(x, y) //This is where the read access violation happens
            };
            }
        }
    }
void Map::draw(sf::RenderWindow *window)
{
    for (int x = 0; x < size; x++) {
        for (int y = 0; y < size; y++) {
            window->draw(tileMap[x][y]);
        }
    }
}

Map.h: Tile is inheriting from base class sf::RectangleShape

#pragma once
#include <iostream>
#include <string>
#include "FastNoise.h"
#include <SFML\Graphics.hpp>
#include "Drawable.h"
#include <memory>
#include "Tile.h"

class Map : public Drawable
{
public:
    Map();
    Map(int size);
    ~Map();
    void draw(sf::RenderWindow *window);

public:
    int size;
    sf::RectangleShape tileMap[5][5];
    FastNoise noiseGenerator;
};

Game.cpp with the main function:

std::list<Drawable*> drawableList;
    int main()
    {

        sf::RenderWindow window(sf::VideoMode(800, 800), "Zieke game");

        Map map{100};
        drawableList.push_front(&map);



        sf::Clock clock;

        while (window.isOpen())
        {
            deltaTime = clock.restart().asSeconds();
            sf::Event event;
            while (window.pollEvent(event))
            {
                if (event.type == sf::Event::Closed)
                    window.close();
            }

            for (auto x : updateableList) {
                x->update(deltaTime);
            }

            window.clear();

            for (auto x : drawableList) {
                x->draw(&window);
            }
            window.display();
        }

        return 0;
    }
\$\endgroup\$
  • 1
    \$\begingroup\$ What do you mean by when I try to add Tiles to the 2D array? How is the array declared? \$\endgroup\$ – tkausl Jul 10 '18 at 18:25
  • \$\begingroup\$ This is done like so: Tile tileMap[100][100]; \$\endgroup\$ – Ian Beemsterboer Jul 10 '18 at 20:28
  • \$\begingroup\$ A big improvement towards maximum array size would be to not store the position of the tile in the tile, since it never changes and you can recalculate it very easily. This would allow you to use a float array, which even if the vector was just 8 bytes would third the size \$\endgroup\$ – Bálint Jul 11 '18 at 2:29
  • \$\begingroup\$ I'm going to suggest a few edits to your question, in order to make it a minimal example that people can test your code and come up with solutions: 1. Show the declaration of the Map class. 2. Show the implementation of the Map class 3. Show the declaration and initialisation of member variables. \$\endgroup\$ – Ian Young Jul 11 '18 at 8:51
  • \$\begingroup\$ I have added asked info in the post. \$\endgroup\$ – Ian Beemsterboer Jul 11 '18 at 9:39
1
\$\begingroup\$

I get a read access violation when I try to add Tiles to the 2D array. What am I doing wrong here?

You declare tileMap like so:

sf::RectangleShape tileMap[5][5];

You access it with tileMap[x][y] in a nested loop inside Map::Map. Both of the loops (over x and over y) have an upper bound of size, which you set to 10 in the first line of the map constructor. That means when x is 0 and y is 5, which it eventually will be, you will begin invoking undefined behavior by accessing the array outside of its bounds. This will generally cause a crash.

In your comments you claimed the tile map is declared as tileMap[100][100]. Perhaps that is what you intended to do instead? Either way, the size variable and the actual declared size of your array are not in sync, and that's causing you trouble. If you make them agree, you should be fine.

I'd suggest you might want to consider looking in to using std::vector to manage your tilemap storage, as well. std::vector is C++'s dynamic array type -- you should probably also use it in place of the std::list you are using for your drawables, which is a linked list.


It is also worth noting that by declaring your array as one of sf::RectangleShape, that is all you can store in the array. When you attempt to assign a Tile to an array element, you slice that Tile, removing all the stuff that makes it a Tile. You probably want your array to be declared as Tile tileMap[whatever][size];.

Also whenever I have an array that is a bit bigger than this one, I get a stack overflow error. Now I read that arrays are kept in stack memory, and the stack is only very small, so what would be a solution to this?

The stack size is generally configurable, but yes, it's usually small-ish by default. The issue is that you are statically declaring your array, which means the entire memory for the array is inline inside an instance of the Map class. You then declare the map instance on the stack (in main), which means the stack must be used to allocate the array memory.

The solution to this is to store the array on the heap, using new. Even better is to use std::vector, which manages the rigmarole of a heap-allocated dynamic array yourself (and is perfectly fine to use for heap-allocated fixed size array as well).

You can make a "2D" vector by doing std::vector<std::vector<Tile>>, but I'd rather recommend you simply flatten the map into a std::vector<Tile> that is width * height elements large; you can access any individual (x, y) element of that linear array as if it were 2D with the calculation y * width + x), like so:

tileMap[y * width + x] = /* ... */;
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.