删除您正在收听的对象?

时间:2011-03-19 05:49:39

标签: c++ callback

这是我的问题:

我正在制作游戏GUI API。它有一个鼠标监听器。让我们说鼠标监听器被指示删除它正在监听的任何小部件。问题是,当它删除它时,迭代器被破坏,因此崩溃:

for(std::vector<AguiMouseListener*>::iterator it 
        = mouseListeners.begin(); it != mouseListeners.end(); ++it)
    {

        switch (event)
        {
        case AguiMouseEventArgs::AGUI_MOUSE_DOWN:
            (*it)->mouseDownCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_UP:
            (*it)->mouseUpCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_MOVE:
            (*it)->mouseMoveCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_CLICK:
            (*it)->mouseClickCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_DOUBLE_CLICK:
            (*it)->mouseDoubleClickCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_WHEEL_UP:
            (*it)->mouseWheelUpCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_WHEEL_DOWN:
            (*it)->mouseWheelDownCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_ENTER:
            (*it)->mouseEnterCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_LEAVE:
            (*it)->mouseLeaveCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_HOVER:
            (*it)->mouseHoverCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_DRAG:
            (*it)->mouseDragCallback(mArgs);
            break;
        case AguiMouseEventArgs::AGUI_MOUSE_MODAL_DOWN:
            (*it)->mouseModalDownCallback(mArgs);
            break;
        default:
            break;
        }
    }

是否有正确的方法让另一个对象删除它从回调中收听的内容?

由于

class BillButton : public AguiMouseListener {
public:
    void mouseLeaveCallback(AguiMouseEventArgs &mouseArgs)
    {
        delete mouseArgs.getSourceWidget();
    }

};

3 个答案:

答案 0 :(得分:1)

  • 您可以使用std :: list而不是std :: vector。 When you remove items from it, you won't invalidate iterators,因此您可以继续循环

  • 您可以构建一个向量/对象列表,在循环结束后将删除这些对象。循环完成后,循环遍历新集合,删除它们,并从原始向量中删除它们。新集合可以是指向指针的类型,因此在迭代时不会销毁它

  • 您可以从回调中添加一个允许某些流量控制的返回值。一个例子是Win32和WinForms事件处理程序如何设置wasHandled标志。在您的情况下,您将告诉处理程序循环是否要终止(以及任何其他听起来有趣/有用的流控制)

  • 您可以重新组织代码,以便在没有更多侦听器(或引用您的对象的其他内容)时使用引用计数智能指针自动删除它。

对于智能指针解决方案,一个这样的类是std::shared_ptr。你可以在brand-spanking-new编译器中找到它(它可能不是标准的,但很快就会出现),或者在the Boost Smart Pointers library中找到。

答案 1 :(得分:0)

我建议从回调中返回一个布尔值,表示回调消耗了该事件。返回true时,循环回调停止。除了删除回调所有者之外,这在其他情况下也很有用。

此外,在调用回调后,请注意不要访问窗口小部件状态。必要时制作所需状态变量的副本。

答案 2 :(得分:0)

您不希望删除仍可处理事件的对象(尤其是当前正在处理的事件)。视图层次结构可以在进攻中交织在一起。

您的处理程序不应该执行删除本身,而是使用父对象注册另一个事件来执行实际删除,然后正常返回(您可能希望在对象上设置一个字段,该字段忽略其他事件,因此它不执行任何操作更多处理)。

当父级获取删除事件时,它会删除计划删除的对象。

我使用术语parent松散地作为视图层次结构中更高的任何对象,包括窗口管理器。