我有这个代码:
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());
}
它采用局部变量的地址。
第一个例子完全安全吗?
我有这个代码:
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());
}
它采用局部变量的地址。
第一个例子完全安全吗?
不捕获任何内容的 lambda 可以隐式转换为具有相同参数列表和返回类型的函数指针。只有无捕获的 lambda 才能做到这一点;如果它捕获任何东西,那么他们就不能。
除非您使用的是 VS2010,它没有实现标准的那部分,因为在他们编写编译器时它还不存在。
In addition to Nicol's perfectly correct general answer, I would add some views on your particular fears:
However, I'm worried that this will suffer the same fate as ..., which takes the address of a local variable.
Of course it does, but this is absolutely no problem when you just call it inside foo
(in the same way your struct example is perfectly working), since the surrounding function (main
in this case) that defined the local variable/lambda will outlive the called function (foo
) anyway. It could only ever be a problem if you would safe that local variable or lambda pointer for later use. So
Is the first example completely safe?
Yes, it is, as is the second example, too.
是的,我相信第一个示例是安全的,无论在评估涉及无捕获 lambda 表达式的完整表达式期间创建的所有临时对象的生命周期如何。
根据工作草案 (n3485) 5.1.2 [expr.prim.lambda] p6
没有 lambda 捕获的 lambda 表达式的闭包类型具有一个公共的非虚拟非显式 const 转换函数,该函数指向具有与闭包类型的函数调用运算符相同的参数和返回类型的函数的指针。这个转换函数的返回值应该是一个函数的地址,当被调用时,它与调用闭包类型的函数调用运算符具有相同的效果。
上面的段落没有说明在评估 lambda 表达式后指向函数的有效性到期。
例如,我希望以下工作:
auto L = []() {
return [](int x, int y) { return x + y; };
};
int foo( int (*sum)(int, int) ) { return sum(3, 4); }
int main() {
foo( L() );
}
虽然 clang 的实现细节肯定不是 C++ 的最终决定(标准是),如果它让你感觉更好,那么在 clang 中实现的方式是,当解析 lambda 表达式并在语义上分析一个闭包类型时发明了 lambda 表达式,并在类中添加了一个静态函数,其语义类似于 lambda 的函数调用运算符。因此,即使 'L()' 返回的 lambda 对象的生命周期已在 'foo' 的主体内结束,转换为指向函数的指针返回仍然有效的静态函数的地址。
考虑一个有点类似的情况:
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.
}
我当然不是 core-c++ 专家,而是 FWIW,这是我对标准字母的解释,我觉得它是可以辩护的。
希望这可以帮助。