同一Lambda的不同定义为何导致C++执行结果差异?
这是个很有意思的问题,核心差异在于**getNum的实际类型以及传递给tester时的行为**,咱们一步步拆解:
第一种情况:使用mylambda函数返回std::function
int main() { auto getNum = mylambda(1); tester(getNum); tester(getNum); }
这里mylambda的返回值明确是std::function<int(void)>,所以getNum的类型就是std::function<int(void)。当你把getNum传给tester时,传递的是这个std::function对象的引用——也就是说两次tester调用共享同一个std::function实例,而这个实例内部持有的是同一个带mutable的lambda对象。
第一次tester调用时,lambda的starter从1开始递增,输出2到11;第二次调用时,starter已经是11了,继续递增输出12到21,所以最终结果是2到21的连续数字。
第二种情况:直接使用立即调用的Lambda返回Lambda
int main() { auto getNum = ([](int starter) { return [starter]() mutable { return ++starter; }; })(1); tester(getNum); tester(getNum); }
这里的关键是:getNum的类型不是std::function,而是那个内部返回的、带mutable的lambda的具体类型(编译器生成的匿名闭包类型)。
当你把getNum传给tester时,因为tester的参数是const std::function<int(void)>&,编译器会每次都创建一个新的std::function实例,并且把getNum(也就是那个lambda)拷贝到这个新的std::function里。
这意味着两次tester调用使用的是两个完全独立的lambda副本:第一次调用时,副本的starter从1递增到11,输出2到11;第二次调用时,新的副本的starter又回到了1,再次输出2到11,所以结果是重复的2到11。
总结一下差异点
- 第一种情况:
getNum是std::function,两次tester共享同一个lambda实例,状态持续累加。 - 第二种情况:
getNum是原始lambda类型,每次传递给tester都会触发std::function的构造,拷贝出独立的lambda实例,状态无法共享。
如果想让第二种情况和第一种行为一致,你可以显式把getNum声明为std::function<int(void)>,比如:
std::function<int(void)> getNum = ([](int starter) { return [starter]() mutable { return ++starter; }; })(1);
这样getNum就是std::function类型,两次传递给tester时共享同一个实例,状态就会持续递增了。
内容的提问来源于stack exchange,提问作者Marco Luzzara

