与函数指针转换相关的lambda对象的生命周期 [英] Lifetime of lambda objects in relation to function pointer conversion

查看:273
本文介绍了与函数指针转换相关的lambda对象的生命周期的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

按照此答案,我现在想知道规则是什么lambdas的生命周期以及如何与通过自动转换创建的函数指针的生命期相关。关于lambdas的生命周期有几个问题(例如这里此处),在这种情况下答案是他们的行为完全一样,你自己写的完整的函子对象,但是没有解决到函数指针的转换,这可能是一个特别的情况。

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;
}

或者只有 retFun1()?问题是:函数指针指向需要调用函子对象本身的函数,还是在单独的函数中重新实现主体?任何一个都有意义,但事实上,转换为函数指针特别需要一个无捕获的lambda表明它可能实际上是后者。

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.

换句话说 - 我可以看到编译器可能想要实现这样的lambdas的两种明智的方式。一个可能的法律实现可能是编译器合成代码,如:

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;
}

在这种情况下 static 和非 - static 的变体 retFun 会很好。然而,如果编译器实现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()是未定义的行为。

then retFun2() is undefined behaviour.

推荐答案

§5.1.2/ 6说:

§5.1.2/6 says:


没有lambda捕获的lambda表达式的闭包类型具有公共非虚拟非显式const转换函数,指向具有与闭包类型相同的参数和返回类型的函数的指针函数调用操作符。此转换函数返回的值将是函数的地址,该函数在调用时具有与调用闭包类型的函数调用运算符相同的效果。

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.

强调我。

换句话说:因为它是一个函数的地址,函数没有生命周期,随时随地调用该函数。

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.

这有点像你所做的:

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
}

这篇关于与函数指针转换相关的lambda对象的生命周期的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆