我目前正在开发一个类的项目,我们正在使用C ++在文本编辑器中实现简单的功能。我们有简单的命令,例如插入一个字符,向左移动,插入一个新行,然后我们有一个撤销/重做功能,其中撤消只是撤消上一个命令的任何内容。并且重做将重做任何刚刚撤消的命令。
首先,我有一个名为Command
的基类,我在其中派生了所有其他类来实现这些命令。到目前为止,我的每个命令都按预期工作,撤消和重做这些命令的简单组合将起作用。
我使用两个向量在我的CommandProcessor
类中实现了undo / redo的功能:
std::vector<Command*> undoVector; // used for undo
std::vector<Command*> redoVector; // used for redo
发出命令时,它会转到if-else中的某个语句,并将该命令存储在undoVector
中。在调用undo时,在撤消命令之前,我将该向量中的命令存储在redoVector
中。当我重做命令时,我将命令重新存储在undoVector
中并发出命令来执行它。
当用户点击退出时,我使用此方法释放向量内存:
void freeVector(std::vector<Command*> &element) {
for(int i = 0; i < element.size(); i++)
{
delete element[i]; // delete command object
}
element.clear(); // clear vector
} // end free vector
在我的程序中,应该始终可以通过使用撤消来回到程序启动的状态,这看起来像这样(其中|是我的光标的位置):< / p>
1. |
目前,如果我发出太多命令要撤消,我会重做几个命令,然后我插入一些命令,撤消那些命令,然后重做那些命令,我无法撤消到我的开头程序。它被一个随机的命令所困,并且不再进一步。
运行memcheck,显示此错误:
==24048== Invalid free() / delete / delete[] / realloc()
==24048== by 0x805CCE0: (anonymous namespace)::freeVector(std::__1::vector<Command*, std::__1::allocator<Command*> >&)
以下是我目前正在实现撤消和重做向量的方法。任何帮助将不胜感激。
void CommandProcessor::run()
{
bool commandInteraction = false;
std::vector<Command*> undoVector; // used for undo
std::vector<Command*> redoVector; // used for redo
view.refresh();
while (true)
{
UserInteraction interaction = nextUserInteraction();
if (interaction.type == UserInteractionType::quit)
{
break;
}
else if (interaction.type == UserInteractionType::undo) // UNDO
{
try
{
if(undoVector.empty())
{
throw EditorException("Nothing to undo.");
} else {
interaction.command = undoVector.back();
redoVector.push_back(interaction.command);
interaction.command->undo(editor);
commandInteraction = false;
undoVector.pop_back();
}
}
catch (EditorException& e)
{
view.showErrorMessage(e.getReason());
}
view.refresh();
}
else if (interaction.type == UserInteractionType::redo) // REDO
{
try
{
// if the redo stack is empty -> we can't redo
// if the last known state was at command -> we can't redo
if(redoVector.empty() || commandInteraction == true)
{
freeVector(redoVector);
throw EditorException("Nothing to redo.");
} else {
interaction.command = redoVector.back();
undoVector.push_back(interaction.command);
interaction.command->execute(editor);
redoVector.pop_back();
view.clearErrorMessage();
}
}
catch(EditorException& e)
{
view.showErrorMessage(e.getReason());
}
view.refresh();
}
else if (interaction.type == UserInteractionType::command) // COMMAND
{
try
{
interaction.command->execute(editor);
commandInteraction = true;
undoVector.push_back(interaction.command);
delete interaction.command;
view.clearErrorMessage();
}
catch (EditorException& e)
{
delete interaction.command;
view.showErrorMessage(e.getReason());
}
view.refresh();
}
} // end while
freeVector(undoVector);
freeVector(redoVector);
} // end run