我的C ++代码中的内存泄漏在哪里?我该如何解决它

时间:2014-06-03 01:25:45

标签: c++ memory-leaks sfml

当我在游戏中加载新关卡时,我的内存泄漏。

每次调用LoadMap()函数时,我的ram会跳得更高,直到程序崩溃,如:

TileGame.exe中0x752dc42d处的未处理异常:Microsoft C ++异常:内存位置为0x003af420的std :: bad_alloc ..

...或

TileGame.exe中0x7787a30e处的未处理异常:0xC0000005:访问冲突读取位置0xfeeefef6。

我正在使用像这样的2d矢量:

//A 2D array of Tile pointers
std::vector<std::vector<Tile*>> map;

//A 2D array of Tile pointers for the background
std::vector<std::vector<Tile*>> background_map;

这是NewLevel()函数,它清除了存储游戏切片的两个地图。该函数还调用LoadMap()函数。

void Level::NewLevel(std::string filename){
    //Generate a new level with Island generator.   
    //IslandGenerator* island = new IslandGenerator();
    this->map.clear();
    this->background_map.clear();

    sf::Image size_image;

    if (!size_image.loadFromFile("data/Levels/" + filename)){
        std::cout << "failed to load image" << std::endl;
        return;
    }

    SetDimensions(size_image.getSize().x, size_image.getSize().y);

    LoadMap(filename);
}

这是我每次加载瓷砖时用来调整地图大小的函数:

void Level::SetDimensions(int w, int h)
{
    this->map.resize(w);
    this->background_map.resize(w);

    //Each row has h columns of null Tile pointers
    for(int i = 0; i < w; i++)
    {
        this->map.at(i).resize(h, 0);
        this->background_map.at(i).resize(h,0);
    }

}

最后,这是LoadMap()函数,它从图像中加载所有图块并设置它们的纹理和属性。

void Level::LoadMap(std::string filename)
{

    // Loads as image to to use the .getSize() operation not allowed for textures
    if (!Image_load.loadFromFile("data/Levels/" + filename))
        std::cout << "failed to load image" << std::endl;

    if (!background_image_load.loadFromFile("data/Levels/background_" + filename))
        std::cout << "failed to load image" << std::endl;

    x_load = Image_load.getSize().x;
    y_load = Image_load.getSize().y;

    this->level_w = x_load;
    this->level_h = y_load;

    player = new Player(entity_texture_manager);

    AddEntity((this->screen_size_x/2)-(player->baseSprite.getLocalBounds().width/2), (this->screen_size_y/2)-(player->baseSprite.getLocalBounds().height/2), player);

    // -----------------------------------------------------------------------

    Tile* new_tile = new Tile();
    Tile* new_background_tile = new Tile();

    for(int ii = 0; ii < y_load; ii++)
    {
        for(int jj = 0; jj < x_load; jj++)
        {

            try
            {
                new_tile = new Tile();
                new_background_tile = new Tile();
            }
            catch (std::bad_alloc& ba)
            {
                std::cerr << "bad_alloc caught: " << ba.what() << '\n';
                return;
            }


            //new_tile = new Tile();
            //new_background_tile = new Tile();

            color_load = Image_load.getPixel (jj, ii);

            // Get the background pixels
            background_color_load = background_image_load.getPixel(jj,ii);


            // Background-----------------------------------------
            if((int)background_color_load.r == 128 && (int)background_color_load.g == 0){
                new_background_tile->setTexture(texture_manager.getTexture(11));
                new_background_tile->color = 11;
                new_background_tile->type = 0;
                new_background_tile->light_blocking_amount = 20;
            }
            else
            {
                new_background_tile->setTexture(texture_manager.getTexture(2));
                new_background_tile->color = 2;
                new_background_tile->type = 0;
                new_background_tile->light_blocking_amount = 20;
            }
            // ---------------------------------------------------

            if((int)color_load.r == 255 && (int)color_load.g == 255){
                new_tile->setTexture(texture_manager.getTexture(3));
                new_tile->color = 3;
                new_tile->type = 1;
            }

            //grass1
            else if((int)color_load.r == 0 && (int)color_load.g == 128 && (int)color_load.b == 128){
            new_tile->setTexture(texture_manager.getTexture(10));
            new_tile->color = 10;
            new_tile->type = 0;
            }

            else if((int)color_load.r == 0 && (int)color_load.g == 128 && (int)color_load.b == 255){
            new_tile->setTexture(texture_manager.getTexture(12));
            new_tile->color = 12;
            new_tile->type = 0;
            }

            else if((int)color_load.r == 0 && (int)color_load.g == 100 && (int)color_load.b == 128){
            new_tile->setTexture(texture_manager.getTexture(13));
            new_tile->color = 13;
            new_tile->type = 0;
            }

            else if((int)color_load.r == 255){
            new_tile->setTexture(texture_manager.getTexture(1));
            new_tile->color = 1;
            new_tile->type = 1;
            }

            else if((int)color_load.g == 255){
            new_tile->setTexture(texture_manager.getTexture(0));
            new_tile->color = 0;
            new_tile->type = 1;
            }

            else if((int)color_load.b == 255){
            new_tile->setTexture(texture_manager.getTexture(2));
            new_tile->color = 2;
            new_tile->type = 0;
            }

            // brick
            else if((int)color_load.g == 128 && (int)color_load.b == 128 && (int)color_load.r == 128){
            new_tile->setTexture(texture_manager.getTexture(9));
            new_tile->color = 9;
            new_tile->type = 1;
            }
            // sand
            else if((int)color_load.r == 128){
            new_tile->setTexture(texture_manager.getTexture(7));
            new_tile->color = 7;
            new_tile->type = 1;
            }
            else if((int)color_load.g == 128){
            new_tile->setTexture(texture_manager.getTexture(8));
            new_tile->color = 8;
            new_tile->type = 1;
            }
            else{
            new_tile->setTexture(texture_manager.getTexture(0));
            new_tile->color = 0;
            new_tile->type = 1;
            }

            //Adds the specified tile to the 2D array

            //cout << map.size() << endl;

            map[jj][ii] = 0;
            background_map[jj][ii] = 0;

            AddTile(jj, ii, new_tile);

            AddBackgroundTile(jj, ii, new_background_tile);

            /*
            //------Ouput Method---------

            for (int r=0; r < map.size(); r++)
            {
                for (int c=0; c < map[r].size(); c++)
                    cout << map[r][c] << '/t';
                cout << endl;
            }

            */

        }


    }   



}

更新

感谢您的评论。我添加了一个删除我的Tile对象的函数,但这似乎仍无效。

我现在称这个功能。

void Level::CleanUp(){


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

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

        }
    }


    this->map.clear();
    this->background_map.clear();

}

我做错了什么想法?

更新2:

这是我的瓷砖类:

class Tile
{

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

    int LightRadius;
    int LightLevel;

    Tile();
    ~Tile();

    sf::Sprite baseSprite;

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

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

更新3:

sprite类是一个内置的sfml类:

////////////////////////////////////////////////////////////
//
// SFML - Simple and Fast Multimedia Library
// Copyright (C) 2007-2014 Laurent Gomila (laurent.gom@gmail.com)
//
// This software is provided 'as-is', without any express or implied warranty.
// In no event will the authors be held liable for any damages arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it freely,
// subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented;
// you must not claim that you wrote the original software.
// If you use this software in a product, an acknowledgment
// in the product documentation would be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such,
// and must not be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//
////////////////////////////////////////////////////////////

#ifndef SFML_SPRITE_HPP
#define SFML_SPRITE_HPP

////////////////////////////////////////////////////////////
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Graphics/Export.hpp>
#include <SFML/Graphics/Drawable.hpp>
#include <SFML/Graphics/Transformable.hpp>
#include <SFML/Graphics/Vertex.hpp>
#include <SFML/Graphics/Rect.hpp>


namespace sf
{
class Texture;

////////////////////////////////////////////////////////////
/// \brief Drawable representation of a texture, with its
/// own transformations, color, etc.
///
////////////////////////////////////////////////////////////
class SFML_GRAPHICS_API Sprite : public Drawable, public Transformable
{
public :

    ////////////////////////////////////////////////////////////
    /// \brief Default constructor
    ///
    /// Creates an empty sprite with no source texture.
    ///
    ////////////////////////////////////////////////////////////
    Sprite();

    ////////////////////////////////////////////////////////////
    /// \brief Construct the sprite from a source texture
    ///
    /// \param texture Source texture
    ///
    /// \see setTexture
    ///
    ////////////////////////////////////////////////////////////
    explicit Sprite(const Texture& texture);

    ////////////////////////////////////////////////////////////
    /// \brief Construct the sprite from a sub-rectangle of a source texture
    ///
    /// \param texture Source texture
    /// \param rectangle Sub-rectangle of the texture to assign to the sprite
    ///
    /// \see setTexture, setTextureRect
    ///
    ////////////////////////////////////////////////////////////
    Sprite(const Texture& texture, const IntRect& rectangle);

    ////////////////////////////////////////////////////////////
    /// \brief Change the source texture of the sprite
    ///
    /// The \a texture argument refers to a texture that must
    /// exist as long as the sprite uses it. Indeed, the sprite
    /// doesn't store its own copy of the texture, but rather keeps
    /// a pointer to the one that you passed to this function.
    /// If the source texture is destroyed and the sprite tries to
    /// use it, the behaviour is undefined.
    /// If \a resetRect is true, the TextureRect property of
    /// the sprite is automatically adjusted to the size of the new
    /// texture. If it is false, the texture rect is left unchanged.
    ///
    /// \param texture New texture
    /// \param resetRect Should the texture rect be reset to the size of the new texture?
    ///
    /// \see getTexture, setTextureRect
    ///
    ////////////////////////////////////////////////////////////
    void setTexture(const Texture& texture, bool resetRect = false);

    ////////////////////////////////////////////////////////////
    /// \brief Set the sub-rectangle of the texture that the sprite will display
    ///
    /// The texture rect is useful when you don't want to display
    /// the whole texture, but rather a part of it.
    /// By default, the texture rect covers the entire texture.
    ///
    /// \param rectangle Rectangle defining the region of the texture to display
    ///
    /// \see getTextureRect, setTexture
    ///
    ////////////////////////////////////////////////////////////
    void setTextureRect(const IntRect& rectangle);

    ////////////////////////////////////////////////////////////
    /// \brief Set the global color of the sprite
    ///
    /// This color is modulated (multiplied) with the sprite's
    /// texture. It can be used to colorize the sprite, or change
    /// its global opacity.
    /// By default, the sprite's color is opaque white.
    ///
    /// \param color New color of the sprite
    ///
    /// \see getColor
    ///
    ////////////////////////////////////////////////////////////
    void setColor(const Color& color);

    ////////////////////////////////////////////////////////////
    /// \brief Get the source texture of the sprite
    ///
    /// If the sprite has no source texture, a NULL pointer is returned.
    /// The returned pointer is const, which means that you can't
    /// modify the texture when you retrieve it with this function.
    ///
    /// \return Pointer to the sprite's texture
    ///
    /// \see setTexture
    ///
    ////////////////////////////////////////////////////////////
    const Texture* getTexture() const;

    ////////////////////////////////////////////////////////////
    /// \brief Get the sub-rectangle of the texture displayed by the sprite
    ///
    /// \return Texture rectangle of the sprite
    ///
    /// \see setTextureRect
    ///
    ////////////////////////////////////////////////////////////
    const IntRect& getTextureRect() const;

    ////////////////////////////////////////////////////////////
    /// \brief Get the global color of the sprite
    ///
    /// \return Global color of the sprite
    ///
    /// \see setColor
    ///
    ////////////////////////////////////////////////////////////
    const Color& getColor() const;

    ////////////////////////////////////////////////////////////
    /// \brief Get the local bounding rectangle of the entity
    ///
    /// The returned rectangle is in local coordinates, which means
    /// that it ignores the transformations (translation, rotation,
    /// scale, ...) that are applied to the entity.
    /// In other words, this function returns the bounds of the
    /// entity in the entity's coordinate system.
    ///
    /// \return Local bounding rectangle of the entity
    ///
    ////////////////////////////////////////////////////////////
    FloatRect getLocalBounds() const;

    ////////////////////////////////////////////////////////////
    /// \brief Get the global bounding rectangle of the entity
    ///
    /// The returned rectangle is in global coordinates, which means
    /// that it takes in account the transformations (translation,
    /// rotation, scale, ...) that are applied to the entity.
    /// In other words, this function returns the bounds of the
    /// sprite in the global 2D world's coordinate system.
    ///
    /// \return Global bounding rectangle of the entity
    ///
    ////////////////////////////////////////////////////////////
    FloatRect getGlobalBounds() const;

private :

    ////////////////////////////////////////////////////////////
    /// \brief Draw the sprite to a render target
    ///
    /// \param target Render target to draw to
    /// \param states Current render states
    ///
    ////////////////////////////////////////////////////////////
    virtual void draw(RenderTarget& target, RenderStates states) const;

    ////////////////////////////////////////////////////////////
    /// \brief Update the vertices' positions
    ///
    ////////////////////////////////////////////////////////////
    void updatePositions();

    ////////////////////////////////////////////////////////////
    /// \brief Update the vertices' texture coordinates
    ///
    ////////////////////////////////////////////////////////////
    void updateTexCoords();

    ////////////////////////////////////////////////////////////
    // Member data
    ////////////////////////////////////////////////////////////
    Vertex m_vertices[4]; ///< Vertices defining the sprite's geometry
    const Texture* m_texture; ///< Texture of the sprite
    IntRect m_textureRect; ///< Rectangle defining the area of the source texture to display
};

} // namespace sf


#endif // SFML_SPRITE_HPP


////////////////////////////////////////////////////////////
/// \class sf::Sprite
/// \ingroup graphics
///
/// sf::Sprite is a drawable class that allows to easily display
/// a texture (or a part of it) on a render target.
///
/// It inherits all the functions from sf::Transformable:
/// position, rotation, scale, origin. It also adds sprite-specific
/// properties such as the texture to use, the part of it to display,
/// and some convenience functions to change the overall color of the
/// sprite, or to get its bounding rectangle.
///
/// sf::Sprite works in combination with the sf::Texture class, which
/// loads and provides the pixel data of a given texture.
///
/// The separation of sf::Sprite and sf::Texture allows more flexibility
/// and better performances: indeed a sf::Texture is a heavy resource,
/// and any operation on it is slow (often too slow for real-time
/// applications). On the other side, a sf::Sprite is a lightweight
/// object which can use the pixel data of a sf::Texture and draw
/// it with its own transformation/color/blending attributes.
///
/// It is important to note that the sf::Sprite instance doesn't
/// copy the texture that it uses, it only keeps a reference to it.
/// Thus, a sf::Texture must not be destroyed while it is
/// used by a sf::Sprite (i.e. never write a function that
/// uses a local sf::Texture instance for creating a sprite).
///
/// See also the note on coordinates and undistorted rendering in sf::Transformable.
///
/// Usage example:
/// \code
/// // Declare and load a texture
/// sf::Texture texture;
/// texture.loadFromFile("texture.png");
///
/// // Create a sprite
/// sf::Sprite sprite;
/// sprite.setTexture(texture);
/// sprite.setTextureRect(sf::IntRect(10, 10, 50, 30));
/// sprite.setColor(sf::Color(255, 255, 255, 200));
/// sprite.setPosition(100, 25);
///
/// // Draw it
/// window.draw(sprite);
/// \endcode
///
/// \see sf::Texture, sf::Transformable
///
////////////////////////////////////////////////////////////

3 个答案:

答案 0 :(得分:1)

您不会删除旧的Tile对象。它们被定义为指针,因此您需要在清除background_map和map之前手动删除它们。

实际上,我根本没有看到任何删除声明。

答案 1 :(得分:1)

根据您发布的信息,我的建议是以这种方式更改您的Tile类,以减轻内存泄漏:

#include <memory>
class Tile
{
    public:
        int type;
        int color;
        int light_level;
        int light_blocking_amount;
        int loc_x, loc_y;

        int LightRadius;
        int LightLevel;
        std::shared_ptr<sf::Sprite> baseSprite;

        Tile();
        //... other member functions
        //
    };

Sprite课程有点复杂,我不知道它是否可以按原样复制(你可以编写一个小测试应用程序来查看Sprite是否是[安全]可复制)。因此,为了安全起见,将其创建为智能指针,并在Tile的构造函数上实例化它。

然后我会用这个:

std::vector<Tile>

而不是

std::vector<Tile*>

构建Tile时,您正在构造一个新的Sprite对象:

Tile::Tile() : baseSprite(new sf::Sprite) 
{
   // whatever else
}

现在Tile类可以用作对象。需要注意的是确保您在shared_ptr中没有循环(阅读shared_ptr使用和循环)。但是根据你发布的代码,我认为不会有,但你应该检查一下。

执行此操作后,将不再需要Tile析构函数,因为shared_ptr将在删除最后一次引用时删除。

答案 2 :(得分:0)

1的第一个循环会立即导致内存泄漏,因为0分配的内存不会被删除。

Tile* new_tile = new Tile(); // <-- 0
Tile* new_background_tile = new Tile(); // <-- 0

for(int ii = 0; ii < y_load; ii++)
{
    for(int jj = 0; jj < x_load; jj++)
    {
        try
        {
            new_tile = new Tile();  // <--- 1
            new_background_tile = new Tile(); // <--- 1
        }