Tommy Tsang
Tommy Tsang

Reputation: 165

Segmentation fault when storing lambda as std::function

The following code gives me segmentation fault. After debugging it, I find out that the problem can be solved by declaring the lambda as auto rather than Function. Why is that the case?

#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;
}

It would be great if I can declare it as Function because I would like to pass this lambda expression to some other classes.

The error that I have when func is declared as Function is:

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

Upvotes: 3

Views: 2988

Answers (2)

molbdnilo
molbdnilo

Reputation: 66371

You need to be careful with function types, and it should work fine if you use the correct one;

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

Perhaps the issue gets clearer with fewer object wrappers and more conventional functions.

What it boils down to, once you remove the indirection through objects, is this:

// 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.
}

This compiles, but g++ warns that the_function returns a reference to a temporary, which is exactly what happens with the std::function (but without so much as a hint from the compiler).

(I'm fairly convinced that allowing this conversion of the returned value in std::function is a mistake. You wouldn't get away with it if you were using function pointers, and C++ is supposed to be more safe than C, not less.)

Upvotes: 1

const Vec&(Vec) is equivalent to a lambda that looks like this (Vec) -> const Vec&. You pass a (const Vec&) -> Vec.

std::function accepts it due to the call sequence containing a valid conversion (You can pass a value to a function expecting a const reference).

The segmentation fault is most likely to the undefined behavior inherent in the return value of your lambda (a temporary) being bound to a const reference in std::function's operator(); that reference is being returned outside of the std::function which immediately makes it a dangling reference.

Upvotes: 6

Related Questions