简体   繁体   中英

c++ Segmentation fault with list iterator

I have trouble accessing an iterator pointing at a list inside a map. Despite the number of similar problems described on internet, I didn't find a correct explanation.

I have a manager object which contains "Visible Object"s ; they are stored in a map when they're single, and in a list inside a map when they can be multiple with a same name. I have some functions that must browse the whole maps, and the program crashes when trying to access the list iterator.

I will try to give you only what's necessary, ask for more if needed.

Manager.h :

class VisibleObject;

class Manager
{
public:
    ~Manager ();

    bool addObject (std::string, VisibleObject*);
    bool addObjectToList (std::string, VisibleObject*);

    bool removeObject (std::string);
    bool removeObjectList (std::string);
    void clean ();

    VisibleObject* getObject (std::string);
    std::list<VisibleObject*>* getObjectList (std::string);

    void updateAll (float);
    void drawAll (sf::RenderWindow&);

private:
    std::map<std::string, VisibleObject*> m_objects;
    std::map<std::string, std::list<VisibleObject*>> m_objectLists;
};

In Manager.cpp :

/// Add a single object
bool Manager::addObject (std::string p_name, VisibleObject* p_object)
{
    std::map<std::string, VisibleObject*>::iterator itr = m_objects.find(p_name);
    if (itr != m_objects.end())
        return false;
    m_objects.insert(std::pair<std::string, VisibleObject*> (p_name, p_object));
    return true;
}

/// Add an object to a list (create list if needed)
bool Manager::addObjectToList (std::string p_name, VisibleObject* p_object)
{
    std::map<std::string, std::list<VisibleObject*>>::iterator itr = m_objectLists.find(p_name);
    if (itr != m_objectLists.end())
    {
        itr->second.push_back(p_object);
        return true;
    } else
    {
        std::list<VisibleObject*> objectList;
        m_objectLists.insert(std::pair<std::string, std::list<VisibleObject*>> (p_name, objectList));
        m_objectLists[p_name].push_back(p_object);
        return false;
    }
}

/// This is where the problem occures
void Manager::drawAll (sf::RenderWindow& p_window)
{
    for (std::map<std::string, VisibleObject*>::iterator itr = m_objects.begin() ; itr != m_objects.end() ; itr++)
        (*itr).second->draw(p_window); // Seems to work fine
    for (std::map<std::string, std::list<VisibleObject*>>::iterator mapItr = m_objectLists.begin() ; mapItr != m_objectLists.end() ; mapItr++)
        for (std::list<VisibleObject*>::iterator listItr = (*mapItr).second.begin() ; listItr != (*mapItr).second.end() ; listItr++)
            (*listItr)->draw(p_window); // This is when I get a segmentation fault while debugging (signal SIGSEGV)
}

There should already be 2 single objects and many listed objects when crashing.

I didn't change the constructor because it doesn't look like something needs to be initialized (The only problem being when accessing the list). VisibleObject::draw(...) is virtual.

EDIT : The manager is an attribute from the static class Game. Here is the part where I can get the manager from any class and a function which add some objects :

Manager& Game::getManager ()
{
    return m_manager;
}

void Game::start ()
{
    Grid *grid = new Grid();
    m_manager.addObject("GRID", grid);
    Tetrimino *tetrimino = new Tetrimino();
    m_manager.addObject("TETRIMINO", tetrimino);
    /* ... */
}

I add Visible Objects in the constructor of the object Grid. I think it doesn't need more explanation :

Grid::Grid ()
{
    VisibleObject::load("ressources/grid.png");
    Square *square = NULL;
    m_gridWidth = Game::getSettings().getInt("GRIDWIDTH");
    m_gridHeight = Game::getSettings().getInt("GRIDHEIGHT");
    m_squares.assign(m_gridWidth*m_gridHeight, square);
    Manager &manager = Game::getManager();
    for (int i=0 ; i<m_gridWidth*m_gridHeight ; i++)
        manager.addObjectToList("SQUARE", square);
}

The Manager's destructor is supposed to delete every objects (but it's not relevant for the problem, is it ?)

The problem is most likely due to dangling pointers. I don't see any code that updates the list in Manager when a VisibleObject gets deleted. Divide the line

(*listItr)->draw(p_window);

into

VisibleObject* object = *listIter;
object->draw(p_window);

Then, you can tell whether the problem is with the list iterator, I suspect it is not, or the problem is caused by a dangling pointer.

When trying to create a list to add objects, this list was declared and deleted in a function (as suggested by R sahu) : here is the wrong code :

std::list<VisibleObject*> objectList;
m_objectLists.insert(std::pair<std::string, std::list<VisibleObject*>> (p_name, objectList));
m_objectLists[p_name].push_back(p_object);

When reaching the end of the "Manager::addObjectToList" function, this list was deleted, but still pointed by the manager. I created it with a pointer instead :

std::list<VisibleObject*>* objectList = new std::list<VisibleObject*>;
m_objectLists.insert(std::pair<std::string, std::list<VisibleObject*>> (p_name, *objectList));
m_objectLists[p_name].push_back(p_object);

EDIT : There was also a problem when I added Squares to an object list : I initialized Squares with a nullptr, the program could not access Square's functions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM