Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Segmentation fault for lambda function in non-static data member initializer

I am unsure about a possible GCC bug in initialization of a std::function from a lambda function capturing this in a non-static data member initializer. Is this allowed by the C++ standard or is this UB?

Given the following code:

#include <functional>
#include <iostream>

template <typename T>
struct A {
      T x = 0;
      std::function<void(T)> f = [this](T v) { x = v; };
};

int main() {
      A<int> a;
      a.f(1);
      std::cout << a.x << "\n";
}

In my understanding, it should print 1. However, when built with GCC 5.4.0 or GCC 6.2.0, a.f(1) emits a segmentation fault, because the captured this pointer is null.

The following alternatives work as I expected:

  • Using constructor initializer list:

    template <typename T>
    struct B {
        B() : f([this](T v) { x = v; }) {}
        T x = 0;
        std::function<void(T)> f;
    };
    
  • Without template:

    struct C {
        int x = 0;
        std::function<void(int)> f = [this](int v) { x = v; };
    };
    

Also, when built with Clang 3.8.0, all three versions behave as I expect, which doesn't mean it is not UB.

like image 885
André Sassi Avatar asked Sep 21 '16 16:09

André Sassi


1 Answers

You cannot do:

template <typename T>
struct A {
    T x = 0;
    std::function<void(T)> f = [this](T v) { x = v; };
};

As this does not exist when you define f. You need to initilize f in a constructor, such as:

A(){ f = [this](T v){ x=v; } }

It worked with G++4.8.

like image 76
jraynal Avatar answered Nov 03 '22 20:11

jraynal