当前位置: 首页 > ds >正文

【Qt/C++】深入理解 Lambda 表达式与 `mutable` 关键字的使用

【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 信号槽连接中修改状态时。

四、输出结果分析

假设用户点击了 myBtnmyBtn2

  1. qDebug() << m; 最初输出 10

  2. 点击 myBtn

    • 输出 110,是 lambda 拷贝的 m 被修改;
  3. 点击 myBtn2

    • 输出 10,lambda 看到的仍是最初的 m 值,因为它是按值捕获的;
    • 没有使用 mutable,无法修改。

五、最佳实践建议

  • 若只需要读取变量,推荐用 [=] 捕获;
  • 若要修改变量拷贝,用 [x] mutable
  • 若想修改外部变量本体,使用 引用捕获 [&x]
  • 警惕 [&] 捕获所有变量引用,虽然方便但易引发生命周期错误。

总结

捕获方式说明可修改?是否影响外部变量
[m]按值捕获变量 m❌ 默认不可以
✅ 使用 mutable
❌ 不影响
[=]按值捕获所有变量
[&m]引用捕获变量 m
[&]引用捕获所有变量

通过这个例子,希望你能对 lambda 表达式的使用和 mutable 关键字有更深入的理解,特别是在 Qt 的信号槽连接中,lambda 是一种高效优雅的解决方案。

http://www.xdnf.cn/news/5294.html

相关文章:

  • MySQL的视图
  • AI 助力,轻松进行双语学术论文翻译!
  • C++GO语言微服务之gorm框架操作MySQL
  • uniapp使用ui.request 请求流式输出
  • LLaVA:开源多模态大语言模型深度解析
  • 物品识别 树莓派4 YOLO v11
  • 青少年编程与数学 02-019 Rust 编程基础 05课题、复合数据类型
  • 解锁 DevOps 新境界 :使用 Flux 进行 GitOps 现场演示 – 自动化您的 Kubernetes 部署
  • 大模型(LLMs)强化学习——RLHF及其变种
  • 基于强化学习 Q-learning 算法求解城市场景下无人机三维路径规划研究,提供完整MATLAB代码
  • linux测试硬盘读写速度
  • uniapp|实现商品分类与列表数据联动,左侧菜单右侧商品列表(瀑布流、高度自动计算、多端兼容)
  • 音频类网站或者资讯总结
  • 电子电器架构 --- 车载以太网拓扑
  • OSPF的四种特殊区域(Stub、Totally Stub、NSSA、Totally NSSA)详解
  • PyTorch 线性回归模型构建与神经网络基础要点解析
  • 数据结构精解:优先队列、哈希表与树结构
  • AI 入门资源:微软 AI-For-Beginners 项目指南
  • Kotlin 协程 vs RxJava vs 线程池:性能与场景对比
  • 【论文阅读】Efficient and secure federated learning against backdoor attacks
  • MySQL 索引(一)
  • 【C++ Qt】容器类(GroupBox、TabWidget)内附思维导图 通俗易懂
  • 发行基础:本地化BUG导致审核失败
  • 动态规划:最长递增子序列
  • 通俗的桥接模式
  • Kubernetes生产实战(十七):负载均衡流量分发管理实战指南
  • 第三天——贪心算法——区间问题
  • 【Java ee初阶】网络编程 UDP socket
  • 无法更新Google Chrome的解决问题
  • 手写系列——transformer网络完成加法和字符转译任务