Lambda回调后违反读取访问权限

时间:2019-01-28 15:55:28

标签: c++ lambda

对于一个小的GUI,我首先想使用函数指针。阅读大量内容后,我发现Lambda回调函数可能是对此更好的解决方案(?)。

我总是会遇到读取访问冲突,并且猜测我缺少一些重要的知识。如果我在lambda调用中使用副本或引用构造函数,则没有区别-我仍然会收到异常。

#include <iostream>
#include <functional>

using namespace std;

//=======================================================

class Button {
private:
    function<void()> const &callback;

public:
    Button(function<void()> const &c) : callback(c) {
        cout << "created Button" << endl;
        callback();     // THIS CALL WORKS FINE
    }

    void update() {
        // if(clicked)...
        callback();     // HERE I GET THE READ ACCESS VIOLATION
    }
};

//=======================================================

class VideoPreview {
private:
    Button *btn;

public:
    VideoPreview() {
        cout << "created VideoPreview" << endl;
        btn = new Button([=]() {
            //cout << "you clicked the button" << endl;
            buttonClicked();
        });
    }

    void update() { // "check the gui"
        btn->update();
    }

    void buttonClicked() {
        cout << "you clicked the button" << endl;
    }

};

//=======================================================

void main() {
    VideoPreview foo;
    foo.update();
}

1 个答案:

答案 0 :(得分:9)

这里的问题是function<void()> const &callback;不会延长从

生成的临时std::function的寿命
btn = new Button([=]() {
    //cout << "you clicked the button" << endl;
    buttonClicked();
});

lambda不是std::function,因此当您执行上述操作时,会生成临时std::function。然后,您使用callback绑定到该临时文件夹,但是const&成员变量不会延长它们绑定到的临时文件夹的寿命。只有函数本地const&会获得该行为。这意味着当退出VideoPreview的构造函数时,会留下一个按钮,该按钮具有对被破坏对象的功能引用。

要解决此问题,只需按值存储callback,例如

class Button {
private:
    function<void()> callback;

public:
    Button(function<void()> c) : callback(std::move(c)) {
        cout << "created Button" << endl;
        callback();     // THIS CALL WORKS FINE
    }

    void update() {
        // if(clicked)...
        callback();     // works now.
    }
};