Reputation: 165
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
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
Reputation: 170065
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