Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Following this answer I'm now wondering what the rules are for the lifetime of lambdas and how the relate to the lifetime of function pointers which are created by automatic conversion. There are several questions about the lifetime of lambdas (e.g. here and here), in which case the answers are "they behave exactly like you wrote the full functor object yourself", however neither address the conversion to function pointer which could quite sensibly be a special case.

I put together this small working example that illustrates my concern:

#include <iostream>

typedef int (*func_t)(int);

// first case
func_t retFun1() {
  static auto lambda = [](int) { return 1; };
  // automatically converted to func_t
  return lambda;
}

// second case
func_t retFun2() {
  // no static
  auto lambda = [](int) { return 2; };
  // automatically converted to func_t and 
  // the local variable lambda reaches the end of its life
  return lambda;
}

int main() {
  const int a = retFun1()(0);
  const int b = retFun2()(0);
  std::cout << a << "," << b << std::endl;
  return 0;
}

Is this well defined for both cases? Or only for retFun1()? The question is: "is the function that the function pointer points required to be calling the functor object itself, or reimplementing the body in a separate function?" Either one would make sense, but the fact that the conversion to function pointer specifically requires a capture-less lambda suggests that it may actually be the latter.


Put another way - I can see at least two sensible ways a compiler might want to implement such lambdas. One possible, legal implementation might be for a compiler to synthesize code like:

func_t retFun3() {
  struct __voodoo_magic_lambda_implementation {
    int operator()(int) const {
      return 3;
    }
    static int plainfunction(int) {
      return 3;
    }
    operator func_t() const {
      return plainfunction;
    }
  } lambda;
  return lambda;
}

in which case both the static and non-static variants of retFun would be fine. If however it's also legal for a compiler to implement the lambda like:

static int __voodoo_impl_function(int x);
static struct __voodoo_maigc_impl2 {
  int operator()(int) const {
    return 4;
  }
  operator func_t() const {
    return __voodoo_impl_function;
  }
} *__magic_functor_ptr;
static int __voodoo_impl_function(int x) {
  return (*__magic_functor_ptr)(x);
}

func_t retFun4() {
  __voodoo_maigc_impl2 lambda;
  // non-static, local lifetime
  __magic_functor_ptr = &lambda; //Or do the equivalent of this in the ctor
  return lambda;
}

then retFun2() is undefined behaviour.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
261 views
Welcome To Ask or Share your Answers For Others

1 Answer

§5.1.2/6 says:

The closure type for a lambda-expression with no lambda-capture has a public non-virtual non-explicit const conversion function to pointer to function having the same parameter and return types as the closure type’s function call operator. The value returned by this conversion function shall be the address of a function that, when invoked, has the same effect as invoking the closure type’s function call operator.

Emphasis mine.

In other words: because it's an address of a function, and functions have no lifetime, you are free to call that function whenever you'd like. Everything you have is well-defined.

It's a bit as if you'd done:

func_t retFun2()
{
    int __lambda0(int)
    {
        return 2;
    }

    struct
    {
        int operator(int __arg0) const
        {
            return __lambda0(__arg0);
        }

        operator decltype(__lambda0)() const
        {
            return __lambda0;
        }
    } lambda;

    return lambda; // just the address of a regular ol' function
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...