Files
scuc-qt-course/docs/teaching/examples/pitfall_lambda_capture/README.md
T
张宗平 6d1895d696 教学示例补 5 个:3 个坑点复现 + QTableWidget + Day5 学员管理器参考实现
- pitfall_stack_widget / pitfall_lambda_capture / pitfall_double_connect:
  默认跑正确写法(离屏验证退出码 0),--crash / --dangle 开关课堂现场触发
  真实崩溃/悬空访问
- table_widget:QTableWidget 单元格事件最小示例(新安排 Day4「表格事件」)
- student_manager:Day5 综合案例参考实现,离屏自测覆盖 JSON round-trip
  与 QThread 后台导入闭环
- 均接入 examples/CMakeLists.txt 的 add_teaching_example,手工维护区不影响生成器
2026-07-05 12:49:20 +08:00

2.0 KiB
Raw Blame History

坑点复现:lambda 槽的生命周期与 connect 第五参数 —— 教学补充示例

对应教案 OUTLINE_4DAY.md Day2 下午 ★坑卡 「lambda 槽的生命周期与第五参数」。手工维护,非生成产物。

概念

connect 的第五参数(context object)决定这条连接跟谁的生命周期挂钩

  • connect(sender, signal, lambda)——连接只跟 sender 挂钩,接收方对象销毁后 lambda 仍会被调用,捕获的指针就是悬空指针;
  • connect(sender, signal, receiver, lambda)——receiver 析构时 Qt 自动断开 连接,lambda 不可能再访问已销毁的对象。

规则:lambda 里捕获了某个 QObject,就把它作为第五参数传进去

运行结果解读

默认运行打印两次 emit 的对比:delete receiver 之后,只有「无 context」的连接 还在触发。--dangle 让这条 lambda 真的去访问已销毁对象——你可能看到程序崩溃, 也可能看到它打印出看似正常的旧值(刚释放的内存还没被复用)。后者更危险: UB 在开发机上「看起来正常」,到了演示/交付现场才炸。

验证与演示方式

QT_QPA_PLATFORM=offscreen tools/run_qt.sh qt_pitfall_lambda_capture            # 确定性对比输出,退出码 0
QT_QPA_PLATFORM=offscreen tools/run_qt.sh qt_pitfall_lambda_capture --dangle   # 课堂演示:真实悬空访问(UB

练习方向(供任务卡引用)

  • 把连接 A 的 lambda 改成按引用捕获一个局部 QString,在函数返回后触发信号, 分析这是哪一种悬空(对象悬空 vs 捕获变量悬空);
  • QObject::destroyed 信号打印 receiver 的销毁时机,确认连接 B 断开发生在何时。

参考

  • 本仓库对照:p03/ch04/lambda_signal_slot.cpplambda 槽基本写法)
  • Qt 官方文档:Differences between String-Based and Functor-Based Connections(选读·需联网)