Recursive lambda and capture (segfault)

Compiler

g++ (Ubuntu 5.2.1-22ubuntu2) 5.2.1 20151010

Fragment 1 ( &capture)

#include <functional>

int main()
{
  std::function<void ()> func = [&] () {
    func();
  };
  return 0;
}

Snipp 2 ( funccapture)

#include <functional>

int main()
{
  std::function<void ()> func = [func] () {
    func();
  };
  return 0;
}

Both fragments are compiled, but why is the second result executed as a result of segmentation?

+4
source share
1 answer

Capture occurs before construction std::function.

So, you commit an uninitialized (not even constructed by default) copy std::function<void()> func. The capture itself std::functionis UB (copying the variable before it is built!), And when called, it will even be "larger than UB" (causing a copy of the non-built std::function!).

func, , , .

, func. , func . , , .

" " , - y-combinator.

++ 14 y-combinator:

template<class F>
auto y_combinate( F&& f ) {
  return [f = std::forward<F>(f)](auto&&...args) {
    return f(f, decltype(args)(args)...);
  };
}

, :

std::function<void ()> func = y_combinate( [](auto&& self) {
    self(self);
  }
);

.

y-combinator , this . .

y-combinator 90%, r/l . .

y-combinate:

template<class F>
struct y_combinate_t {
  F f;
  template<class...Args>
  decltype(auto) operator()(Args&&...args)const {
    return f(*this, std::forward<Args>(args)...);
  }
};
template<class F>
y_combinate_t<std::decay_t<F>> y_combinate( F&& f ) {
  return {std::forward<F>(f)};
}

:

std::function<void ()> func = y_combinate( [](auto&& self) {
    self();
  }
);

self, , self .

+3

Source: https://habr.com/ru/post/1618119/


All Articles