0

私はSDLでタイルベースのマップをプログラミングしており、クラスのコンストラクターを使用して、その中に含まれる各オブジェクトMapを表すために使用されるイメージを設定しています。ただし、オブジェクトが保持しているオブジェクトを解放するために使用されているクラスMapCellのデストラクタに問題があります。デストラクタは早く呼ばれていますが、その理由はよくわかりません。これは、セルのスプライトがどのように割り当てられるかを示した、コンストラクターの簡略版です。SpriteSDL_Surface*Map

Map::Map(string fileName, int tileWidth, int tileHeight)
{   
    string mapData = ReadMap(fileName);
    _cells = new MapCell[_width*_height];

    for(int y = 0; y < _height; y++)
    {
        for(int x = 0; x < _width; x++)
        {
            int currentCell = y*_width+x;

            if(mapData[currentCell] == '0' || mapData[currentCell] == 'P' || mapData[currentCell] == 'X')
            {
                _cells[currentCell]._sprite = Sprite(Point2D(x*tileWidth, y*tileHeight), "Assets/Graphics/Grass.bmp");
                if(mapData[currentCell] == 'P')
                    _cells[currentCell]._sprite = Sprite(Point2D(x*tileWidth, y*tileHeight), "Assets/Graphics/Player.bmp");
                if (mapData[currentCell] == 'X')
                    _cells[currentCell]._sprite = Sprite(Point2D(x*tileWidth, y*tileHeight), "Assets/Graphics/Target.bmp");
            }
            else if(mapData[currentCell] == '1')
                _cells[currentCell]._sprite = Sprite(Point2D(x*tileWidth, y*tileHeight), "Assets/Graphics/Wall.bmp");
        }
    }
}

デストラクタは、Spriteオブジェクトが作成された直後に呼び出されたようです。ここで何が欠けていますか?_spriteのメンバーをヒープに割り当てようとしましMapCellたが、同じ問題が発生します。私の知る限り、Sprite作成されたオブジェクトはオブジェクトの一部であるため、スコープから外れることはありませんMap

Sprite以下は、クラスのコンストラクタとデストラクタです。

Sprite::Sprite(void)
{
    _texture = NULL;
    _position = Point2D::Zero();
}

Sprite::Sprite(Point2D position, std::string texPath)
{
    _texture = Content::LoadBMP(texPath);
    _position = position;
}

Sprite::~Sprite(void)
{
    SDL_FreeSurface(_texture);
}

それがまったく役立つ場合は、これが私のメインです:

int main( int argc, char* args[] )
{
    const int TILEWIDTH = 32;
    const int TILEHEIGHT = 32;

    // Initialization
    InitSDL();
    Map map = Map("Assets/Maps/Map3.txt", TILEWIDTH, TILEHEIGHT);
    Window::SetSize(Rectangle(0, 0, map.GetWidth()*TILEWIDTH, map.GetHeight()*TILEHEIGHT));

    PathFinder pathFinder = PathFinder();
    List<Point2D> path = pathFinder.FindPath(map, map.GetPlayerStart(), map.GetTarget());
    List<Sprite> PathNodes = List<Sprite>();
    for(int i = 0; i < path.GetCount(); i++)
        PathNodes.Add(Sprite(*path(i)*32, "Assets/Graphics/PathNode.bmp"));

    bool quit = false;
    SDL_Event Event;

    while(quit == false)
    {
        while(SDL_PollEvent(&Event))
        {
            if(Event.type == SDL_QUIT)
                quit = true;
        }

        map.Draw();

        for(int i = 0; i < path.GetCount(); i++)
        {
            if(PathNodes(i)->GetPosition() != map.GetPlayerStart()*32 && PathNodes(i)->GetPosition() != map.GetTarget()*32)
                PathNodes(i)->Blit();
        }

        Window::Flip();
    }

    //Quit SDL
    SDL_Quit();

    return 0;    
}
4

2 に答える 2

3

問題は割り当てx._sprite = Sprite(...)です。これにより、一時的な が作成され、Spriteそのフィールドが にコピーされてから、一時的な が破棄されます。さらに、割り当てを行う前にデストラクタを呼び出さないため、古いものがリークするだけです。_sprite_sprite_texture

それを回避したい場合は、コピーではなく の内容を更新する.setor.load関数を使用し、偶発的な悪用を避けるためにプライベート割り当てとコピー コンストラクター メソッドを作成します。SpriteSprite

于 2013-02-27T11:22:43.450 に答える
2
for(int i = 0; i < path.GetCount(); i++)
        PathNodes.Add(Sprite(*path(i)*32, "Assets/Graphics/PathNode.bmp"));
                    // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                    // a temporary here!

その式が終了すると、temporary のデストラクタSpriteが呼び出され、サーフェスPathNodesが解放され、解放されたサーフェスへのダングリング ポインタを持つオブジェクトが残ります。あなたのコードには、おそらくもっと多くのそのような式があります。

3 つのルールに従い、適切なコピー コンストラクターとSpriteクラスの代入演算子を記述します。

のドキュメントを参照して、SDL_Surface何を行う必要があるかを確認してください (refcountサーフェスのメンバーを手動でインクリメントする必要がある場合があります)。

于 2013-02-27T11:24:15.487 に答える