将 lambda 存储为 std::function 时出现分段错误

Segmentation fault when storing lambda as std::function

以下代码给出了分段错误。调试后,我发现可以通过将lambda 声明为auto 而不是Function 来解决问题。为什么会这样?

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

typedef std::vector<double> Vec;
typedef std::function<const Vec&(Vec)> Function;


int main()
{
     //Function func = [](const Vec& a)->Vec /*this give me segfault*/
     auto func = [](const Vec& a)->Vec /*this work just fine??*/
         {
              Vec b(2);
              b[0] = a[0] + a[1];
              b[1] = a[0] - a[0];
              return b;
         };
     Vec b = func(Vec{1,2});
     std::cout << b[0] << " " << b[1] << "\n";
     return 0;
}

如果我能将它声明为 Function 就好了,因为我想 将此 lambda 表达式传递给其他 类。

将 func 声明为 Function 时出现的错误是:

Program received signal SIGSEGV, Segmentation fault. 0x0000000000401896 in std::vector >::size (this=0x0) at /usr/include/c++/5/bits/stl_vector.h:655 655 { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); }
(gdb) backtrace
#0 0x0000000000401896 in std::vector >::size (this=0x0) at /usr/include/c++/5/bits/stl_vector.h:655
#1 0x00000000004015aa in std::vector >::vector (this=0x7fffffffdc50, __x=) at /usr/include/c++/5/bits/stl_vector.h:320
#2 0x0000000000400d12 in main () at test.cxx:18

const Vec&(Vec) 相当于一个看起来像这样的 lambda (Vec) -> const Vec&。你传一个(const Vec&) -> Vec.

std::function 由于包含有效转换的调用序列而接受它(您可以将值传递给需要 const 引用的函数)。

分段错误最有可能是您的 lambda(临时)的 return 值中固有的未定义行为被绑定到 std::functionoperator() 中的 const 引用;该引用在 std::function 之外被 returned,这立即使它成为悬空引用。

您需要注意函数类型,如果您使用正确的类型,它应该可以正常工作;

typedef std::function<Vec(const Vec&)> Function; 

也许随着更少的对象包装器和更多的常规函数​​,问题会变得更清楚。

一旦你删除了通过对象的间接寻址,它归结为:

// const Vec& -> Vec
std::vector<double> the_lambda(const std::vector<double>& x)
{
    return x;
}

// Vec -> const Vec&
const std::vector<double>& the_function(std::vector<double> x)
{
    return the_lambda(x);
}


int main()
{
    std::vector<double> v = {1, 2};
    std::vector<double> lv = the_lambda(v);    // OK.
    std::vector<double> fv = the_function(v);  // Undefined.
}

这可以编译,但是 g++ 会警告 the_function returns 对临时对象的引用,这正是 std::function 所发生的情况(但没有来自编译器)。

(我相当确信在 std::function 中允许返回值的这种转换是错误的。如果你使用函数指针,你就不会逃脱它,而 C++ 应该是比 C 更安全,不少于。)