Как удалить 2D вектор указателей на объекты без утечки памяти? C++ и SFML

У меня есть 2D вектор указателей плитки. Каждый раз, когда я загружаю другую карту, я хотел бы удалить все плитки в векторе, освобождая память, а затем снова заполнить ее разными плитками.

std::vector<std::vector<Tile*>> map;

Вот мой класс плитки:

#ifndef _TILE_H
#define _TILE_H

#include <SFML\Graphics.hpp>

class Tile
{

public:
    int type;
    int color;
    int light_level;
    int loc_x, loc_y;

    Tile();
    ~Tile();

    sf::Sprite baseSprite;

    void Draw(int x, int y, sf::RenderWindow* rw);

    void setTexture(sf::Texture& texture);
};

#endif

Я заполняю векторы вот так:

map[x][y] = tile;

Проблема в том, что каждый раз, когда я добавляю векторы с Tiles, моя память продолжает заполняться, пока игра не вылетает. У меня вопрос, как я могу правильно удалить все из векторов, чтобы освободить память?

Вот моя попытка удалить плитки, которые не освободили память:

for(int ii = 0; ii < this->map.size(); ii++){
    for(int jj = 0; jj < this->h; jj++){

        delete &this->map[ii][jj]->baseSprite;
        delete &this->map[ii][jj]->color;
        delete &this->map[ii][jj]->light_level;
        delete &this->map[ii][jj]->loc_x;
        delete &this->map[ii][jj]->loc_y;
        delete &this->map[ii][jj]->type;

        delete &this->map[ii][jj];
    }
}


map.clear() 

Если потребуется какой-либо дополнительный код, пожалуйста, дайте мне знать, спасибо.

1 ответ

Решение

Судя по Tile класс, кажется, глупо использовать Tile указатели вместо непосредственного использования Tileв вашем векторе. Вот возможное решение вашей проблемы:

  1. Определить конструктор копирования, т.е. определить, что Tile::Tile(const Tile&) должен сделать (он должен скопировать все элементы данных во вновь созданную плитку).
  2. Определить оператор присваивания, т.е. определить, что Tile& Tile::operator=(const Tile&) должен сделать (это должно вызвать все operator= функционирует на всех своих членах данных и return *this).

На первый взгляд это кажется нормальным, но я посмотрел на sf::Sprite документация, и ни конструктор копирования, ни оператор присваивания не определены для sf::Sprite, Кажется, спрайты могут быть созданы только через sf::Texture, К счастью, каждый sf::Sprite предоставляет публичную функцию-член, которая возвращает свою собственную границу sf::Texture, Тем не менее, глядя на документацию sf::Sprite::getTexture(), он возвращает указатель на sf::Textureчто может быть NULL если никакая текстура еще не связана с sf::Sprite, Вы должны проверить это в конструкторе копирования и операторе присваивания для Tile,

Конструктор копирования должен выглядеть примерно так:

Tile::Tile(const Tile& other)
: type(other.type)
, color(other.color)
, light_level(other.light_level)
, loc_x(other.loc_x)
, loc_y(other.loc_y)
, baseSprite()
{
    sf::Texture* result = other.baseSprite.getTexture();
    if (result)
    {
        baseSprite.setTexture(*result);
    }
}

и оператор присваивания должен выглядеть примерно так:

Tile& Tile::operator = (const Tile& other)
{
    type = other.type;
    color = other.color;
    light_level = other.light_level;
    loc_x = other.loc_x;
    loc_y = other.loc_y;
    sf::Texture* result = other.baseSprite.getTexture();
    if (result)
    {
        baseSprite.setTexture(*result);
    }
    return *this;
}

Там больше, чем это, хотя, кажется, sf::Sprite также может быть определен под прямоугольником текстуры, и он, вероятно, имеет больше свойств, о которых нужно позаботиться. Например, sf::Sprite также есть геттеры и сеттеры для его положения, поворота, его глобального цвета, все, что вам нужно скопировать. В любом случае, как только это будет сделано, вы можете забыть о беспорядке указателя и создать экземпляр

std::vector<std::vector<Tile> >

вместо.

Другие вопросы по тегам