lambda – C 0x闭包的未定义行为:II
我发现使用C 0x闭包令人困惑.我的初始
report和
subsequent one产生了比解释更多的混乱.下面我将向您展示麻烦的示例,我希望找出代码中存在未定义行为的原因.代码的所有部分都没有任何警告地通过gcc 4.6.0编译器.
计划1:它的工作原理 #include <iostream> int main(){ auto accumulator = [](int x) { return [=](int y) -> int { return x+y; }; }; auto ac=accumulator(1); std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; } 产量符合预期: 2 2 2 2 2 2 2 2 2 2.第2号方案:关闭,工作正常 #include <iostream> int main(){ auto accumulator = [](int x) { return [&](int y) -> int { return x+=y; }; }; auto ac=accumulator(1); std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; } 输出是: 4 3 2 7 6 5 10 9 8 程序3:带有std :: function的程序1,Works Fine #include <iostream> #include <functional> // std::function int main(){ typedef std::function<int(int)> fint2int_type; typedef std::function<fint2int_type(int)> parent_lambda_type; parent_lambda_type accumulator = [](int x) -> fint2int_type{ return [=](int y) -> int { return x+y; }; }; fint2int_type ac=accumulator(1); std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; } 输出是: 2 2 2 2 2 2 2 2 2 程序4:带有std :: function,Undefined Behavior的程序2 #include <iostream> #include <functional> // std::function int main(){ typedef std::function<int(int)> fint2int_type; typedef std::function<fint2int_type(int)> parent_lambda_type; parent_lambda_type accumulator = [](int x) -> fint2int_type{ return [&](int y) -> int { return x+=y; }; }; fint2int_type ac=accumulator(1); std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; } 该计划的第一次运行给出: 4 3 2 4 3 2 12364812 12364811 12364810 第二轮同一程序: 4 3 2 4 3 2 1666060 1666059 1666058 第三个: 4 3 2 4 3 2 2182156 2182155 2182154 我如何使用std :: function打破代码?为什么程序1 – 3运行良好,而程序4正确调用ac(1)三次(!)?为什么4号程序卡在接下来的三个案例中,好像变量x已被值捕获,而不是参考.并且ac(1)的最后三个调用完全不可预测,好像对x的任何引用都将丢失. 解决方法
每次我处理复杂而复杂的lambda时,我觉得首先将其转换为函数 – 对象形式会更容易.因为lambdas只是函数对象的语法糖,并且对于每个lambda,都存在与对应的函数对象的一对一映射.本文解释了如何进行翻译: 例如,你的程序没有2: #include <iostream> int main(){ auto accumulator = [](int x) { return [&](int y) -> int { return x+=y; }; }; auto ac=accumulator(1); std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; } 将由编译器大致翻译成这一个: #include <iostream> struct InnerAccumulator { int& x; InnerAccumulator(int& x):x(x) { } int operator()(int y) const { return x+=y; } }; struct Accumulator { InnerAccumulator operator()(int x) const { return InnerAccumulator(x); // constructor } }; int main() { Accumulator accumulator; InnerAccumulator ac = accumulator(1); std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; std::cout << ac(1) << " " << ac(1) << " " << ac(1) << " " << std::endl; } 现在,问题变得非常明显: InnerAccumulator operator()(int x) const { return InnerAccumulator(x); // constructor } 这里InnerAccumulator的构造函数将引用x,这是一个局部变量,一旦退出operator()范围就会死亡.所以,是的,你只是得到了一个明确的旧的未定义的行为,因为你怀疑. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |