C++11.Lambda 成员变量捕获,"this" STL 列表中的指针陷阱



我有一个简单的事件系统与简单的按钮。这个系统是由std::function list驱动的,里面赋值了lambdas。

这里是完整的按钮类:

class Button {
private:
    Square square;
    Text label;
    bool hovered = false;
    std::function <void ()> on_mouse_enter;
    std::function <void ()> on_mouse_leave;
public:
    Button (const Square& SQUARE, const Text& LABEL):
        square {SQUARE},
        label {LABEL}
    {
        on_mouse_enter = [this] () {
            square.set_color(1, 1, 1);
        };
        on_mouse_leave = [this] () {
            square.set_color(0, 0, 0);
        };
    }
    std::function <void (const Render&)> get_rendering() {
        return [this] (const Render& RENDER) {
            RENDER.draw(square);
            RENDER.draw(label);
        };
    }
    std::function <void (const Point&)> get_updating() {
        return [this] (const Point& CURSOR) {
            if (not hovered) {
                if (is_including(square, CURSOR)) {
                   hovered = true;
                   if (on_mouse_enter)
                       on_mouse_enter();
                }
            } else
                if (not is_including(square, CURSOR)) {
                   hovered = false;
                   if (on_mouse_leave)
                       on_mouse_leave();
                }
        };
    }
};

我添加这样的按钮到事件管理器,像这样:

Button button {/*SOME_PARAMS_HERE*/};
mngr.push_to_render(button.get_render());
mngr.push_to_updater(button.get_updater());

它工作完美,没有问题,on_mouse_enteron_mouse_leave工作正常。

但是如果我用STL容器包装器做一些事情,像这样:

std::list <Button> sb;
sb.emplace_back(Button {/*SOME_PARAMS_HERE*/});
mngr.push_to_render(sb.back().get_render());
mngr.push_to_updater(sb.back().get_updater());

整件事正在分崩离析。on_mouse_enteron_mouse_leave不能正常工作。

通过输出调试消息,我可以看到,在on_mouse_enteron_mouse_leave中由this访问的正方形不是它们应该是的正方形,接下来我看到this不是它应该是什么。

这种捕获有什么问题?如何解决?

如果你要被复制,不要捕获this。无论您捕获什么,您都要负责管理其生命周期。

第二,将指向按钮的指针传递给enter/leave是很有意义的。

std::function<void(Button*)> on_mouse_enter;
std::function<void(Button*)> on_mouse_leave;

然后是:

    on_mouse_enter = [] (Button* but) {
        but->square.set_color(1, 1, 1);
    };
    on_mouse_leave = [] (Button* but) {
        but->square.set_color(0, 0, 0);
    };

和复制构造函数不再给你留下指向另一个this的指针。

最后,调用on_mouse_enter时,传递this

最新更新