【问题标题】:Segfault while composing vector of lambda functions组成 lambda 函数向量时的段错误
【发布时间】:2018-04-04 16:33:30
【问题描述】:

我正在尝试创建一个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)

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

使用打印语句和 GDB 进行调试的注意事项:

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

【问题讨论】:

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


    【解决方案1】:

    创建的每个 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)); };
    

    【讨论】:

    • 很好。 [&amp;]!此修改足以修复它:f = [=](int x) { return (*f_begin)(f(x)); };
    • @joydeepb 好的,但我也不想捕获迭代器。如果你的functions 向量发生了变化,compositions 仿函数可能会死掉。
    • @ascepler 这是真的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    • 2020-04-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多