lambda表达式值捕获的一点小疑问

问题

学习C++时,版本是C++03,公司也没有升级编译器,一直没有学习C++11,后来换工作后,新公司提倡使用C++11,特别推荐槽函数直接使用lambda如下所示写法:

1
2
connect(ui->pushButton, &QPushButton::clicked, [=]() {
});

大佬推荐[]中,一般直接捕获=即可。

后来大体了解了一下捕获:

[&](以引用隐式捕获被使用的自动变量)

[=] (以复制隐式捕获被使用的自动变量)。

[=, &i] // 以复制捕获,但 i 以引用捕获

但是有点疑问:

dialog.h

1
2
3
4
5
6
7
8
9
10
11
12
class Dialog : public QDialog
{
Q_OBJECT

public:
Dialog(QWidget *parent = nullptr);
~Dialog();

private:
Ui::Dialog *ui;
int clickedCount_ = 0;
};

dialog.cpp

1
2
3
4
5
6
7
8
9
10
11
12
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Dialog)
{
ui->setupUi(this);
clickedCount_;

connect(ui->pushButton, &QPushButton::clicked, [&]() {
clickedCount_++;
ui->label->setText(QString::number(clickedCount_));
});
}

以上代码实现在按钮点击时,显示点击次数

我之前的想法是:由于lambda中以引用隐式自动捕获clickedCount_[&]),所以当点击按钮时,clickedCount_++能改变被捕获的clickedCount_值,如果换成以复制隐式捕获被使用的自动变量[=],那么当点击按钮时,将一直显示0。

测试一下:

dialog.cpp

1
2
3
4
5
6
7
8
9
10
11
12
Dialog::Dialog(QWidget *parent)
: QDialog(parent)
, ui(new Ui::Dialog)
{
ui->setupUi(this);
clickedCount_;

connect(ui->pushButton, &QPushButton::clicked, [=]() {
clickedCount_++;
ui->label->setText(QString::number(clickedCount_));
});
}

功能和按引用捕获完全一样,不讲武德啊。。。。

解决

查看文档得知:

Lambda 捕获

捕获 是零或更多捕获符的逗号分隔列表,可选地以 默认捕获符 开始。仅有的默认捕获符是

&(以引用隐式捕获被使用的自动变量)和

= (以复制隐式捕获被使用的自动变量)。

当出现任一默认捕获符时,都能隐式捕获当前对象(*this)。当它被隐式捕获时,始终被以引用捕获,即使默认捕获符是 = 也是如此。

原来是因为无论是[=]还是[&]都会默认捕获*this的引用,所以上面的示例得到的结果是一样的。

找到原因后,心中的疑团终于解决了,值还会捕获引用,总感觉有点怪怪的。

继续向下看文档:

当默认捕获符为 = 时,*this 的隐式捕获被弃用。 (C++20 起)

那帮老头子们是不是也感觉=捕获引用不妥,c++20给取消了。

感觉更不讲武德了。。。。

Effective Modern C++建议避免使用默认捕获模式

Effective Modern C++