C++ 使用C++;11 lambda函数将单击事件连接到函数

C++ 使用C++;11 lambda函数将单击事件连接到函数,c++,qt,c++11,lambda,C++,Qt,C++11,Lambda,在GUI应用程序中,我使用了很多按钮。这些按钮标记为pbxx,其中xx是网格布局中按钮的行号和列号。按下按钮时,需要突出显示该按钮。今天我读了关于lambda函数的内容&我想我会尝试在代码中实现它 在我的GUI显示类(继承QMainWindow的类)中,我有一个名为: make_connections(); 这将使我的所有按钮连接(所有信号都连接到按钮点击()上的单个插槽)。我在这里添加了代码: GuiDisplay类 GuiDisplay类的make_connections函数 构建给了我

在GUI应用程序中,我使用了很多按钮。这些按钮标记为
pbxx
,其中
xx
是网格布局中按钮的行号和列号。按下按钮时,需要突出显示该按钮。今天我读了关于lambda函数的内容&我想我会尝试在代码中实现它

在我的GUI显示类(继承QMainWindow的类)中,我有一个名为:

make_connections(); 
这将使我的所有按钮连接(所有信号都连接到按钮点击()上的单个插槽
。我在这里添加了代码:

GuiDisplay类 GuiDisplay类的make_connections函数 构建给了我以下错误

'pb_label' is not captured
所以我想,好吧,那么做以下事情似乎没有错:

connect(pb_ptr, &QPushButton::clicked, [this, &pb_label]{on_pushbutton_clicked(pb_label);});

构建时的错误消失了,但是每当执行此代码时,我的GUI应用程序意外崩溃。不确定原因。这里有任何帮助吗?

谢谢Piotr Skotnicki和Simple,您的建议都很有效。我可能应该读得更深入一些,我会在捕获列表中看到[=]

因此,导致问题的一行代码可以是:

connect(pb_ptr, &QPushButton::clicked, [this, pb_label]{on_pushbutton_clicked(pb_label);});


谢谢Piotr Skotnicki和Simple,你的两个建议都很有效。我可能应该读得更深入一点,我会在捕获列表中看到[=]

因此,导致问题的一行代码可以是:

connect(pb_ptr, &QPushButton::clicked, [this, pb_label]{on_pushbutton_clicked(pb_label);});


您的错误是由于使用了对临时标签的引用。
pb_标签
仅在
GuiDisplay::make_connections
期间存在。您的lambda由Qt存储,并且将在每次触发信号时被引用。发生这种情况时,您将引用已销毁的对象

因此,建立连接的正确方法是:

connect(pb_ptr, &QPushButton::clicked, [=]{ on_pushbutton_clicked(pb_label); });
从Qt 5.2开始,添加了过载,该过载将在对象生命周期结束时自动断开。在这种情况下,连接将是:

connect(pb_str, &QPushButton::clicked, this, [=]{ on_pushbutton_clicked(pb_label); });

也就是说,当您可以简单地执行以下操作时,不应在此处使用lambda:

connect(pb_ptr, &QPushButton::clicked, this, &GuiDisplay::on_pushbutton_clicked);
然后修改您的
GuiDisplay::on_button_clicked
以不接受任何参数。您可以通过调用:来获取
GuiDisplay::on_button_clicked
中的对象名称,这将:

返回指向发送信号的对象的指针

然后只需使用获取
pb\u标签

此属性包含此对象的名称

因此,您只需将
pb\u标签
替换为:
sender()->objectName()

直接插槽连接优于lambda的原因有几个:

  • 它不需要为
    pb\u标签存储临时lambda和临时
    QString
  • 它删除了需要额外堆栈帧的lambda间接寻址
  • 调试到lambdas并不总是对开发人员友好的,尽管一些ide缓解了这个问题
  • :
  • “接收器”被销毁时不会自动断开连接,因为它是一个没有
    QObject
    的函子


    您的错误是由于使用了对临时标签的引用。
    pb_标签
    仅在
    GuiDisplay::make_connections
    期间存在。您的lambda由Qt存储,并且将在每次触发信号时被引用。发生这种情况时,您将引用已销毁的对象

    因此,建立连接的正确方法是:

    connect(pb_ptr, &QPushButton::clicked, [=]{ on_pushbutton_clicked(pb_label); });
    
    从Qt 5.2开始,添加了过载,该过载将在对象生命周期结束时自动断开。在这种情况下,连接将是:

    connect(pb_str, &QPushButton::clicked, this, [=]{ on_pushbutton_clicked(pb_label); });
    

    也就是说,当您可以简单地执行以下操作时,不应在此处使用lambda:

    connect(pb_ptr, &QPushButton::clicked, this, &GuiDisplay::on_pushbutton_clicked);
    
    然后修改您的
    GuiDisplay::on_button_clicked
    以不接受任何参数。您可以通过调用:来获取
    GuiDisplay::on_button_clicked
    中的对象名称,这将:

    返回指向发送信号的对象的指针

    然后只需使用获取
    pb\u标签

    此属性包含此对象的名称

    因此,您只需将
    pb\u标签
    替换为:
    sender()->objectName()

    直接插槽连接优于lambda的原因有几个:

  • 它不需要为
    pb\u标签存储临时lambda和临时
    QString
  • 它删除了需要额外堆栈帧的lambda间接寻址
  • 调试到lambdas并不总是对开发人员友好的,尽管一些ide缓解了这个问题
  • :
  • “接收器”被销毁时不会自动断开连接,因为它是一个没有
    QObject
    的函子


    按值捕获
    pb_标签
    ,即
    [这个,pb_标签]
    或者您可以使用
    [=]
    按值捕获
    pb_标签
    ,即
    [这个,pb_标签]
    或者您可以使用
    [=]
    FWIW,当通过引用捕获时,
    [这个,&pb_标签]
    ,然后是原始对象(捕获的引用指向的对象)在退出
    建立连接时被销毁,这就是为什么您会遇到崩溃fwiw,当通过引用捕获时,
    [此,&pb_标签]
    ,然后是原始对象(捕获的引用指向该对象)从
    make_connections
    退出时被破坏,这就是为什么你会遇到crashesI我认为值得一提的是,假设使用Qt 5.2或更新版本,如果你需要在某个对象被破坏时自动断开连接,你可以将该对象作为@thuga Fair point传递,实际上我甚至从我引用的Qt wiki中删除了它。我从来没有r费心从Qt 5.1升级,我在一种没有人使用Qt 5.2的非理性思维下工作。我已经更新了答案。我认为值得一提的是,假设使用Qt 5.2或更新版本,如果在某个对象被销毁时需要自动断开连接,可以将该对象作为