运行中自我销毁的Lambda行为探究及代码未定义行为确认
Lambda运行中自我销毁的行为及你的代码问题分析
嘿,咱们一步步来理清楚你的问题:
一、Lambda运行时执行自我销毁会咋样?
简单来说,这会触发未定义行为——C++标准完全不保证这种情况下的程序行为,可能某次运行正常,下次直接崩溃,甚至出现莫名其妙的逻辑错误,完全看编译器和内存布局的“脸色”。
具体到场景里:
- 如果Lambda是值捕获变量,这些捕获的副本虽然在Lambda销毁前就存好了,但Lambda本身的函数对象已经被销毁,继续执行它的代码相当于在操作一块已经被释放的内存,风险极高。
- 如果是引用捕获,那引用的变量可能也跟着被销毁,问题会更严重。
- 像你代码里用的
std::function,当你给它赋值nullptr时,它会立刻销毁当前持有的Lambda对象。要是这个Lambda此时还在执行中,就等于你在调用一个已经被“干掉”的对象的函数,这完全违反了C++对象生命周期的规则。
二、你的代码确实存在未定义行为,这就是崩溃的根源
先贴你的代码方便分析:
#include <functional> #include <iostream> struct T { void bar() { auto callback = []() { std::cout << 42 << '\n'; }; foo = [this, callback]() { // Object holding the bound lambda is destroyed foo = nullptr; // Captured function invoked callback(); }; } std::function<void()> foo; }; int main() { T t; t.bar(); t.foo(); }
问题出在这两步的顺序:
当你调用t.foo()时,执行的是bar()里赋值给foo的Lambda:
- 第一步执行
foo = nullptr:这行代码会让std::function立刻销毁它当前持有的Lambda对象——而这个对象,就是现在正在执行的这个Lambda本身! - 第二步执行
callback():虽然callback是值捕获的副本,本身生命周期没问题,但承载当前执行代码的Lambda对象已经被销毁了。在C++里,对象销毁后,它的所有成员(包括Lambda闭包里的内部状态)都不再有效,继续执行这个对象的函数体,就是标准的未定义行为。
这就是你遇到周期性崩溃的原因:未定义行为的表现是不确定的,有时候内存布局刚好没出问题,程序就正常跑了;有时候触发了内存访问错误,就直接崩溃了。
三、怎么修复?
核心思路就是:别在Lambda还在执行的时候销毁它。最简单的办法就是调整顺序,先执行完callback(),再重置foo:
foo = [this, callback]() { // 先把回调执行完,再重置foo callback(); foo = nullptr; };
这样就避免了“在对象运行中销毁它”的问题,程序行为就变得确定了。
内容的提问来源于stack exchange,提问作者Lightness Races in Orbit
相关产品推荐
相关产品推荐

