【Qt/C++】深入理解 Lambda 表达式与 mutable
关键字的使用
在 Qt 开发中,我们常常会用到 lambda
表达式来编写简洁的槽函数。今天通过一个实际代码示例,详细讲解 lambda
的语法、变量捕获方式,特别是 mutable
的作用。
示例代码
QPushButton * myBtn = new QPushButton(this);
QPushButton * myBtn2 = new QPushButton(this);
myBtn2->move(100, 100);
int m = 10;
connect(myBtn, &QPushButton::clicked, this, [m]() mutable {
m = 100 + 10;
qDebug() << m;
});
connect(myBtn2, &QPushButton::clicked, this, [=]() {
qDebug() << m;
});
qDebug() << m;
一、Lambda 表达式基本结构
Lambda 表达式的完整语法如下:
[capture](parameter_list) mutable -> return_type {
// function body
};
每个部分含义如下:
[capture]
:捕获列表,决定 lambda 能访问哪些外部变量以及如何访问;(parameter_list)
:传入 lambda 的参数;mutable
(可选):允许修改捕获的变量副本;-> return_type
(可选):指定返回类型;{ ... }
:函数体。
二、示例中的捕获方式说明
connect(myBtn, ..., [m]() mutable {...})
[m]
表示 按值捕获 变量m
。lambda 拿到的是m
的拷贝;mutable
关键字允许修改这个拷贝,否则按值捕获的变量在 lambda 中默认是const
的;- 这段代码中,
m = 100 + 10;
是合法的,因为mutable
去除了m
的只读限制; - 需要注意,这种修改只作用在拷贝上,不影响外部的
m
。
connect(myBtn2, ..., [=]() {...})
[=]
表示 按值捕获所有外部变量;- 没有加
mutable
,所以 lambda 内部对m
是只读的; qDebug() << m;
打印的是外部m
的原始值,即10
。
三、mutable
的关键作用
默认情况下,按值捕获的变量在 lambda 中是 const
的:
int x = 5;
auto func = [x]() {
x = 10; // 编译错误!x 是 const
};
加上 mutable
后就允许修改:
int x = 5;
auto func = [x]() mutable {
x = 10; // 合法,修改的是 x 的副本
};
这在一些涉及临时变量处理的场景中非常有用,尤其是在 Qt 信号槽连接中修改状态时。
四、输出结果分析
假设用户点击了 myBtn
和 myBtn2
:
qDebug() << m;
最初输出10
;点击
myBtn
:- 输出
110
,是 lambda 拷贝的m
被修改;
- 输出
点击
myBtn2
:- 输出
10
,lambda 看到的仍是最初的m
值,因为它是按值捕获的; - 没有使用
mutable
,无法修改。
- 输出
五、最佳实践建议
- 若只需要读取变量,推荐用
[=]
捕获; - 若要修改变量拷贝,用
[x] mutable
; - 若想修改外部变量本体,使用 引用捕获
[&x]
; - 警惕
[&]
捕获所有变量引用,虽然方便但易引发生命周期错误。
总结
捕获方式 | 说明 | 可修改? | 是否影响外部变量 |
---|---|---|---|
[m] |
按值捕获变量 m | ❌ 默认不可以 ✅ 使用 mutable |
❌ 不影响 |
[=] |
按值捕获所有变量 | ❌ | ❌ |
[&m] |
引用捕获变量 m | ✅ | ✅ |
[&] |
引用捕获所有变量 | ✅ | ✅ |
通过这个例子,希望你能对 lambda
表达式的使用和 mutable
关键字有更深入的理解,特别是在 Qt 的信号槽连接中,lambda
是一种高效优雅的解决方案。