它是安全蒙上了lambda函数的函数指针?(Is it safe to cast a lambda

2019-07-28 05:43发布

我有这样的代码:

void foo(void (*bar)()) {
    bar();
}

int main() {
    foo([] {
        int x = 2;
    });
}

不过,我担心这会遭受同样的命运:

struct X { int i; };

void foo(X* x) {
    x->i = 2;
}

int main() {
    foo(&X());
}

这需要一个局部变量的地址。

是第一个例子完全安全?

Answer 1:

捕获任何一个lambda是其相同的参数列表,返回类型隐式转换为一个函数指针。 只捕获少lambda表达式可以做到这一点; 如果它抓住任何东西,那么他们不能。

除非你使用VS2010,没有不实施该标准的一部分,因为它不存在,然而,当他们正在写自己的编译器。



Answer 2:

除了尼科尔的完全正确的笼统的回答,我想补充你的特定恐惧的一些看法:

不过,我担心这会遭受同样的命运......,这需要一个局部变量的地址。

当然有,但这是绝对没有问题的时候,你只需要调用它的内部foo (在你的结构例子是完美的工作方法相同),因为周围的功能( main是定义的局部变量在这种情况下)/λ会活得比被调用的函数( foo )反正。 它只能永远是一个问题,如果你愿意的安全是局部变量或供以后使用拉姆达指针。 所以

是第一个例子完全安全?

是的,它是,因为是第二个例子,太。



Answer 3:

是的,我相信,第一个例子是安全的,不管充分表达,涉及捕捉少拉姆达表达式的评估过程中创建的所有临时对象的生命时间。

每工作草案(n3485)5.1.2 [expr.prim.lambda] P6

对于没有拉姆达捕获一个lambda表达式的闭合类型有一个公共非虚非显式const的转换功能函数指针具有相同的参数和返回类型为封闭类型的函数调用操作符。 通过这种转换函数的返回值应是一个函数调用时,与调用闭合类型的函数调用操作的效果相同的地址。

上面这段只字未提拉姆达表达的评估后的指针到函数的有效期到期。

对于例如,我希望下面的工作:

auto L = []() {
   return [](int x, int y) { return x + y; };
};

int foo( int (*sum)(int, int) ) { return sum(3, 4); }


int main() {
  foo( L() );
}

虽然铿锵的实现细节肯定不是在C ++(标准为)一锤定音,如果它让你感觉更好,这是在铛实现的方式是,当lambda表达式解析和语义分析的一个闭合式的λ表达式被发明的,并静态功能被添加到类具有类似于拉姆达的函数调用操作的语义。 因此,即使“()L”返回的拉姆达对象的生命时间是在“富”的身体内,转化为指针到函数返回一个静态的功能仍然有效的地址。

考虑有些analagous情况:

struct B {
   static int f(int, int) { return 0; }
   typedef int (*fp_t)(int, int);
   operator fp_t() const { return &f; }
};
int main() {
  int (*fp)(int, int) = B{};
  fp(3, 4); // You would expect this to be ok.
}

我当然不是一个核心的C ++专家,但FWIW,这是我的标准的信的解释,我觉得这是可防御的。

希望这可以帮助。



文章来源: Is it safe to cast a lambda function to a function pointer?