yoni0505
yoni0505

Reputation: 359

C++ - Object is destroyed before the destructor is executed

I have a class which have a 2D vector of pointers to dynamically allocated instances (wallGameObjects) which I want to delete when the destructor is called, but by the time the destructor executes the vector is already destroyed.

The destructor calls removeMaze():

MazeSceneBuilder::~MazeSceneBuilder()
{
    removeMaze();

    mSceneManager->destroySceneNode(mazeNode);
}

And the object's member variables are already gone:

void MazeSceneBuilder::removeMaze()
{
    // Remove walls
    for (unsigned int x = 0; x < mazeWidth; x++)
    {
        for (unsigned int z = 0; z < mazeWidth; z++)
        {
            if (wallGameObjects[x][z] != nullptr)
            {
                mGameObjectManager->removeGameObject(wallGameObjects[x][z]);
            }
        }
    }

    // remove ground
    mGameObjectManager->removeGameObject(groundGameObject);

    // Destroy collision shapes
    destroyCollisionShapes();
}

Breakpoint on the line "mGameObjectManager->removeGameObject(groundGameObject);" shows this:

this    0x00000000 <NULL>   MazeSceneBuilder *

It doesn't make sense to me. I tried to call "removeMaze()" before the object is destroyed and it worked just fine. Are the object's members suppose to be gone before the destructor executes?

EDIT:

As requested, here's the destructor of MultiplayerMaze:

MultiplayerMaze::~MultiplayerMaze()
{
    destroyPhysicsWorld();
}

destroyPhysicsWorld:

void MultiplayerMaze::destroyPhysicsWorld()
{
    delete dynamicsWorld;
    delete solver;
    delete collisionConfiguration;
    delete dispatcher;
    delete broadphase;
}

EDIT 2:

MultiplayerMaze class definition:

class MultiplayerMaze : public BaseApplication
{
public:
    MultiplayerMaze();
    virtual ~MultiplayerMaze();

protected:
    virtual void createScene();
    virtual bool frameRenderingQueued(const Ogre::FrameEvent& evt);
    virtual bool configure();

    virtual void createPhysicsWorld();
    virtual void destroyPhysicsWorld();

    // Physics members
    btBroadphaseInterface* broadphase;
    btDefaultCollisionConfiguration* collisionConfiguration;
    btCollisionDispatcher* dispatcher;
    btSequentialImpulseConstraintSolver* solver;
    btDiscreteDynamicsWorld* dynamicsWorld;

    GameObjectManager gameObjectManager;

    MazeSceneBuilder mazeSceneBuilder;
    MazeGenerator mazeGenerator;
};

MazeSceneBuilder class definition:

class MazeSceneBuilder
{
protected:
    std::vector<std::vector<bool>> mMaze;
    unsigned int mazeWidth, mazeHeight;
    float mMazeScale;

    GameObjectManager* mGameObjectManager;
    Ogre::SceneManager* mSceneManager;
    Ogre::String mWallEntity;
    Ogre::String mGroundMaterial;
    Ogre::Entity* mGround;
    Ogre::SceneNode* mazeNode;
    btCollisionShape* wallCollisionShape;
    btCollisionShape* collisionPlanes[5];
    GameObject* groundGameObject;
    std::vector<std::vector<GameObject*>> wallGameObjects;

    void setupGround();     // Creates a plane entity using the ground materiala and the maze size.
    void createCollisionShapes();       // Create collision shapes for the wall, ground, and bounding planes.
    void destroyCollisionShapes();
    void DestroyAllAttachedMovableObjects(Ogre::SceneNode* sceneNode);

public:
    MazeSceneBuilder();
    MazeSceneBuilder(GameObjectManager* gameObjectManager);
    ~MazeSceneBuilder();

    void setGameObjectManager(GameObjectManager* gameObjectManager);
    bool setMaze(std::vector<std::vector<bool>> maze);      // Returns false if the provided maze was invalid.
    void setMazeScale(float scale);
    void setWallEntity(Ogre::String entityName);        // Must be a square cuboid of 1x2x1
    void setGroundMaterial(Ogre::String materialName);  // Should be a tiled square texture.
    void buildMaze();
    void updateMaze(const std::vector<std::vector<bool>>& maze);
    void removeMaze();
};

Upvotes: 1

Views: 563

Answers (1)

ragazzojp
ragazzojp

Reputation: 519

This is probably not related to the destructor, but please have a look at:

// Remove walls
for (unsigned int x = 0; x < mazeWidth; x++)
{
    for (unsigned int z = 0; z < mazeWidth; z++)
    {
        if (wallGameObjects[x][z] != nullptr)
        {
            mGameObjectManager->removeGameObject(wallGameObjects[x][z]);
        }
    }
}

You use mazeWidth twice. Shouldn't you use mazeHeight? If mazes are not square, you may end up using some uninitialized pointer in wallGameObjects, with unforeseeable side effects, especially if those objects have a destructor that destroys other objects, and so on.

As the classes are complex, I suggest using std::unique_ptr<T> when possible to model ownership. It will help you tracking the bug.

Upvotes: 1

Related Questions