C++ lambda闭包捕获Cow函数局部weight变量失效问题求助
问题根因
核心问题是局部变量的生命周期和闭包捕获的生命周期不匹配:
- Cow函数内定义的
weight是栈上分配的局部变量,当Cow函数执行完毕返回后,对应的栈帧会被系统回收,weight占用的内存也会随之失效。 - 代码中使用的
[&]是引用捕获,闭包内部保存的是weight的内存地址,当你在main函数中调用getWeight/setWeight时,访问的已经是被回收的野地址,自然会读到未初始化的值,修改也不会生效,极端情况下还会触发程序崩溃。
另外要注意,直接把捕获方式改成值捕获[=]也无法解决问题:值捕获会让每个闭包各自持有一份weight的拷贝,setWeight修改的是自身闭包内的副本,getWeight读取的是自己闭包里的初始值,两个闭包的数据不互通,同样达不到预期效果。
修复方案
这里提供两种常用的可行方案:
方案1:将weight作为Mammal结构体的成员变量(最符合面向对象设计的方案)
直接把weight放到Mammal结构体中,生命周期和Mammal对象完全绑定,不需要闭包捕获外部变量:
#include <iostream> #include <functional> struct Mammal { int weight = 0; std::function<void()> speak; std::function<int()> getWeight; std::function<void(int)> setWeight; }; Mammal *Cow() { auto *m = new Mammal(); m->weight = 100; m->speak = []() { puts("momo~~ momo~~"); }; m->getWeight = [m]() { return m->weight; }; m->setWeight = [m](int w) { m->weight = w; }; return m; } int main() { Mammal *c = Cow(); std::cout << "Cow Weight: " << c->getWeight() << '\n'; c->setWeight(200); std::cout << "Cow New Weight: " << c->getWeight() << '\n'; // 释放堆内存避免泄漏 delete c; return 0; }
方案2:用智能指针托管weight,按值捕获智能指针
如果你不想修改Mammal的结构体定义,可以用shared_ptr把weight放到堆上,捕获的时候按值拷贝智能指针,引用计数机制会保证weight的生命周期和闭包一致:
#include <iostream> #include <functional> #include <memory> struct Mammal { std::function<void()> speak; std::function<int()> getWeight; std::function<void(int)> setWeight; }; Mammal *Cow() { auto weight = std::make_shared<int>(100); auto *m = new Mammal(); m->speak = []() { puts("momo~~ momo~~"); }; // 按值捕获shared_ptr,两个闭包共享同一个weight实例 m->getWeight = [weight]() { return *weight; }; m->setWeight = [weight](int w) { *weight = w; }; return m; } int main() { Mammal *c = Cow(); std::cout << "Cow Weight: " << c->getWeight() << '\n'; c->setWeight(200); std::cout << "Cow New Weight: " << c->getWeight() << '\n'; delete c; return 0; }
内容的提问来源于stack exchange,提问作者user3674011
相关产品推荐
相关产品推荐

