【问题标题】:How to delete a 2D vector of object pointers without a memory leak? C++ and SFML如何在没有内存泄漏的情况下删除对象指针的二维向量? C++ 和 SFML
【发布时间】:2014-07-28 01:17:09
【问题描述】:

我有一个 2D 平铺指针向量。每次我加载不同的地图时,我想删除矢量中的所有瓷砖,释放内存,然后用不同的瓷砖重新填充它。

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

这是我的 Tile 类:

#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() 

如果需要任何额外的代码,请告诉我,谢谢。

【问题讨论】:

  • 不确定是否有足够的信息来很好地回答这个问题。但是使用智能指针可能不是一个坏主意。
  • 您需要查找 RAII。删除一个 tile 应该有一个析构函数来处理它的成员。
  • 看看智能指针,尤其是std::unique_ptr。如果您不能使用它,请查看 boost 前身。
  • 你为什么要删除Tile的每个成员?它们本身不是指针,你有 UB.
  • 是的,删除 Tile 的每个成员并没有做任何事情。我正在研究 std::unique_ptr

标签: c++ pointers memory-leaks sfml 2d-vector


【解决方案1】:

Tile 类来看,在向量中使用Tile 指针而不是直接使用Tiles 似乎很愚蠢。以下是您的问题的可能解决方案:

  1. 定义一个复制构造函数,即定义Tile::Tile(const Tile&amp;) 应该做什么(它应该将所有数据成员复制到新构建的磁贴)。
  2. 定义赋值运算符,即定义Tile&amp; Tile::operator=(const Tile&amp;) 应该做什么(它应该调用所有operator= 对其所有数据成员和return *this 的函数)。

现在乍一看这似乎没问题,但我查看了sf::Sprite 文档,并没有为sf::Sprite 定义复制构造函数和赋值运算符。似乎只能通过sf::Texture 创建精灵。幸运的是,每个 sf::Sprite 都公开了一个公共成员函数,该函数返回其自己的绑定 sf::Texture。然而,查看sf::Sprite::getTexture() 的文档,它返回一个指向sf::Texture指针,如果还没有纹理绑定到sf::Sprite,它可能是NULL。您应该在 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 也有用于位置、旋转、全局颜色的 getter 和 setter,所有这些都需要复制。无论如何,一旦完成,您就可以忘记指针混乱并实例化

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

改为。

【讨论】:

  • 感谢您的解决方案。我已经尝试实施这个解决方案几个小时了。我终于使用没有指针的 2D 矢量运行了游戏。但是,它加载图块的速度比以前慢得多。这应该发生吗?无论如何,感谢到目前为止的所有帮助!
  • 我对为什么会这样有一些想法,但是这个聊天框对于那个对话来说太小了。您可以给我发电子邮件(请参阅我的个人资料页面上的电子邮件地址)以继续会议。
猜你喜欢
  • 1970-01-01
  • 2023-03-26
  • 2013-04-06
  • 2021-12-19
  • 2011-04-16
  • 2013-09-30
  • 2012-11-15
  • 2019-03-31
  • 1970-01-01
相关资源
最近更新 更多