Segfault在组成lambda函数的向量时

时间:2017-10-24 01:54:26

标签: c++ c++11 lambda functional-programming higher-order-functions

我正在尝试创建一个接受函数向量的compose_all lambda,并返回一个函数,该函数是向量中所有函数的组合:

#include <algorithm>
#include <iostream>
#include <vector>
#include <functional>

using std::cout;
using std::endl;
using std::function;
using std::vector;

int main() {
  vector<function<int(int)>> functions = {
    [](int x) { return 2 * x; },
    [](int x) { return x * x; },
    [](int x) { return -x; },
  };

  function<function<int(int)>(
      vector<function<int(int)>>::iterator,
      vector<function<int(int)>>::iterator,
      function<int(int)>)> compose_all;
  compose_all = [&](vector<function<int(int)>>::iterator f_begin,
                    vector<function<int(int)>>::iterator f_end,
                    function<int(int)> f) -> function<int(int)> {
    for (; f_begin < f_end; ++f_begin) {
      f = [&](int x) { return (*f_begin)(f(x)); };
    }
    return f;
  };

  auto composition = compose_all(functions.begin(),
                                 functions.end(),
                                 [](int x) { return x; });

  for (int i = 0; i < 10; ++i) {
    cout << composition(i) << endl;
  }
  return 0;
}

虽然这个编译很好,但它是段错误的:

$ clang++ -std=c++11 -g composition.cpp && ./a.out 
Segmentation fault (core dumped)

段错误的原因是什么,以及解决方法是什么?

使用print语句和GDB调试的注意事项:

  • compose_all
  • 正确接收了迭代器
  • 段错误发生在f = [&](int x) { return (*f_begin)(f(x)); };
  • 单独取消引用f_begin会产生正确的结果(它会在向量中调用正确的lambda)

1 个答案:

答案 0 :(得分:2)

创建的每个lambda
f = [&](int x) { return (*f_begin)(f(x)); };

通过引用捕获ff_begin,其中两者都是存储在compose_all中的lambda主体的本地。

这些函数的最后一个函数在被调用时由compose_all包含lambda的主体返回,然后被赋值给composition。但是由于compose_all的lambda的主体已经退出,ff_begin的生命周期已经结束,并且调用composition是未定义的行为。

此外,你真的不希望f调用自己,这只会让你无限递归。您希望f从其当前值(即初始值,或您之前指定的f)中调用f值的副本。

您需要以下内容:

const auto& g = *f_begin;
f = [=](int x) { return g(f(x)); };

(或者在C ++ 14或更高版本中,这可以写成:)

f = [f, g=*f_begin](int x) { return g(f(x)); };