Undo redo with automatic deletion mechanism

My application is being developed in C ++ using Qt and uses signals and slots.

Let's say I have the following classes (pseudo C ++ code):

class Ball
{
    Color m_Color;
    int m_Size;
};

class Player
{
public:
    setBall(Ball* pBall)
    {
        if (pBall != m_pBall)
        {
            Ball* pPreviousBall = m_pBall;
            m_pBall = pBall;
            emit notifyBallNotUsed(pPreviousBall);
        }
    }

    Ball* getBall();

signals:
    void notifyBallNotUsed(Ball*);

private:
    String m_Name;
    Ball* m_pBall;
};

class GeneralHandler
{
public:
    addBall(Ball* pBall);
    deleteBall(Ball* pBall);


    addPlayer(Player* pPlayer)
    {
        connect(pPlayer, SIGNAL(notifyBallNotUsed(Ball*)), this, SLOT(onBallUsageChanged(Ball*)));
        ...
    }
    deletePlayer(Player* pPlayer);
    {
        disconnect(pPlayer, SIGNAL(notifyBallNotUsed(Ball*)), this, SLOT(onBallUsageChanged(Ball*)));

        onBallUsageChanged(pPlayer->getBall());
        ....
    }

private slots:
    void onBallUsageChanged(Ball* pBall)
    {
        if (isNotUsedAnymore(pBall))
        {
            m_BallList.remove(pBall);
            delete pBall;
        }
    }

private:
    bool isNotUsedAnymore(Ball* pBall); // Check if the given ball is still used by at least one player

    List<Player*> m_PlayerList;
    List<Ball*> m_BallList;
};

      

In my application, the user can add / remove a player, and for each player, select the color and size of the ball. Behind the hood, the GeneralHandler is responsible for storing the balls and removing them. It is possible that two players are using the same ball.

When a player is removed if the ball is no longer in use, the GeneralHandler must remove it (or keep it if the ball is still in use by another player). If the ball that the player is using changes, the previous ball, if no longer in use, must also be removed by General Handler.

So far so good.

Now I want to add undo / redo functionality to my application using command pattern and this is where I am stuck. Let's say I have something like this:

class ChangePlayerBall : public QUndoCommand
{
public:
    ChangePlayerBall(Player* pPlayer, Ball* pNewBall)
    {
        m_pPlayer = pPlayer;
    }

    void redo();
    void undo();

private:
    Player* m_pPlayer;
};

      

I think the redo () method will look like this:

void ChangePlayerBall::redo()
{
    m_pPlayer->setBall(pNewBall);
}

      

If nothing has changed in the code above, the previous ball will be removed if it is no longer used by other players. This will be a problem when implementing the undo () method: if the previous ball was deleted, I don't know what its characteristics were, and the undo command won't be able to recreate it. Or maybe I should keep the previous ball, but how does the undo / redo command know if this previous ball still exists or has been removed by the handler? Or maybe this mechanism for removing the ball, once it is no longer used, should be implemented in the undo command? The problem is that the undo command will have many dependencies on many other classes. Another problem is that this code will be partially duplicated in the DeletePlayer command, which should do something like this:

class DeletePlayer : public QUndoCommand
{
public:
    DeletePlayer(Player* pPlayer);

    void redo();
    void undo();
...
};

      

Hope my explanation is clear!

How would you solve this problem? I cannot find a satisfactory solution.

Thank!

0


source to share


3 answers


How about using a reference ball trick? When the ball is in the team, the team can increment the reference count for the ball, so it prevents the handler from deleting it (or by itself, depending on how you changed the implementation).



0


source


The ball is removed if it is not used more by other players

As I see it is s the source of your doubts. Certainly undo() command shouldn't recreate an object nor have it

its own deletion mechanism. How does your GeneralHandler.isNotUsedAnymore () work? If it is counting balls references, it should also count the reference to the ChangePlayerBall instance. Therefore, you will need to bind the Command object to some GeneralHandler slots.

So, I would suggest:



  • The ball is removed if it is not used by any player and any UndoCommands (may include color change, etc.)
  • The connection between the ball and the player's brake when assigning a new ball as you did
  • The relationship between balls and commands on the command object descriptor (when completely removed from the stack)

Hope it helps)

+1


source


  • Save the ball in the command constructor.
  • Insert / as needed.
  • Use QSharedPointer for globally globally to prevent memory leaks.
0


source







All Articles