1

我一直在尝试用 C++ 编写一种用于游戏的简单“窗口”系统,它在游戏区域中绘制可以有按钮等的窗口(在游戏自己的图形内部,即不是操作系统的 GUI 窗口)。窗口对象(这里称为“类 Window”)具有一些事件方法,例如按键,以及在接收到该事件时挂钩要调用的处理程序的能力。

窗口被(或将被)收集在“窗口管理器”中,并且窗口对象将具有“close()”成员,该成员将调用父窗口管理器的窗口删除例程来删除自身。一个连接到,比如说,窗口上的按钮的事件处理程序可能会调用这个例程来关闭窗口(想象一个“OK”框)。

问题是这听起来像是一个 " delete *this;" 声明,我听说这是一个no-no。确实,它不会直接这样做,但效果是一样的:一个对象有一个成员函数会导致它自己的销毁(例如“close()”函数,或者触发处理程序的事件函数导致“close()”函数被调用。)。如果这很糟糕,那么设计它的更好方法是什么?

4

1 回答 1

4

对象删除自身并没有错。您必须简单地告诉窗口管理器从它的集合中删除该窗口,然后再删除。如果您让窗口管理器删除窗口对象,那就更好了。

如果你真的想避免这种行为,你可以在bool dead;每个初始化为false. 当要关闭窗口时,设置this->dead = true;. 每一帧,让窗口管理器遍历它的窗口并删除那些死掉的窗口。

请注意,此解决方案仍然无法修复引用已删除窗口的外部系统引起的错误,但它确实具有集中删除窗口的优势。

我设计了很多游戏的窗口系统,根据我的经验,允许窗口删除自己是一个非常优雅的解决方案,即使它更容易出错。

一个最小的例子:

class Window
{
  public:
    void keyPressCallback(int c)
    {
      if (c == KEY_ESC)
      {
        manager.destroy(this);
        return;
      }
    }
    WindowManager& manager;
};

class WindowManager
{
  public:
    void destroy(Window* target)
    {
      delete target;
      windows.erase(std::find(windows.begin(), windows.end(), target));
    }
    std::vector<Window*> windows;
};

只要没有指向该窗口的剩余指针,此方法就完全安全且语义健全。当窗口收到关闭信号时,它会自行关闭。

dead带有标志的相同示例:

class Window
{
  public:
    Window() : dead(false) {}
    void keyPressCallback(int c)
    {
      if (c == KEY_ESC)
      {
        dead = true;
        return;
      }
    }
    bool dead;
};

class WindowManager
{
  public:
    void cleanup()
    {
      for (auto iter = windows.begin(); iter != windows.end(); ++iter)
      {
        if (iter->dead) windows.erase(iter);
      }
    }
    std::vector<Window*> windows;
};
于 2013-03-24T06:46:29.717 回答