Search code examples
c++lambdareferencesegmentation-faultconstants

Returning const reference from lambda stored as std::function segfaults


Here is the code:

#include <vector>
#include <functional>

class TestClass {
public:
    const std::vector<int> &getStuff() const {
        return callback();
    }

protected:
    std::function<const std::vector<int> &()> callback = []() {
        static const std::vector<int> dummy;
        return dummy;
    };
};

int main()
{
  TestClass test;

  const auto& vec = test.getStuff();
  vec.size();  // segfault

  return 0;
}

I don't understand why it should behave like this. I suspect some "known" rule about lambdas or std::functions but I cannot seem to find the right keywords for this problem so here I am.

Tested on GCC 11 and Clang 14 Ubuntu.


Solution

  • With this lambda:

    []() {
            static const std::vector<int> dummy;
            return dummy;
        };
    

    The compiler infers that the return value is std::vector<int> by value (and not a reference to std::vector<int>).

    Then when it is converted to a std::function<const std::vector<int> &()> the std::function will return a reference to the temporary copy returned from the lambda.

    This reference is dangling and hence your SEGFAULT.

    In order to fix it, you can specify the return type for the lambda explicitly:

    //---vvvvvvvvvvvvvvvvvvvvvvvvvv--
    []() -> const std::vector<int>& {
            static const std::vector<int> dummy;
            return dummy;
        };
    

    Live demo 1

    As @Evg commented below, you can also use auto & to achieve the same result (the compiler will deduce the proper type and use a referece due to the &):

    []() -> auto & {
           // ...
        }
    

    Live demo 2