2

我在玩 bind,我在想,lambdas 和函数指针一样贵吗?

我的意思是,据我了解 lambda,它们是函子的语法糖,并且 bind 是相似的。但是,如果您这样做:

#include<functional>
#include<iostream>

void fn2(int a, int b)
{
  std::cout << a << ", " << b << std::endl;
}

void fn1(int a, int b)
{
  //auto bound = std::bind(fn2, a, b);
  //static auto bound = std::bind(fn2, a, b);
  //auto bound = [&]{ fn2(a, b); };
  static auto bound = [&]{ fn2(a, b); };
  bound();
}

int main()
{
  fn1(3, 4);
  fn1(1, 2);
  return 0;
}

现在,如果我使用 1st auto bound = std::bind(fn2, a, b);,我会得到一个输出

3、4

1, 2

,第二个我得到
3、4

3、4

. 第三个和第四个我得到像第一个一样的输出。

现在我明白了为什么第一个和第二个以这种方式工作,它们在函数调用开始时被初始化(静态的,只有第一次被调用)。然而,3 和 4 似乎有编译器的魔力,其中生成的函子并没有真正创建对封闭范围变量的引用,而是实际上锁定了符号,无论它是否仅在第一次或每次初始化。

有人可以澄清这里实际发生的事情吗?

编辑:我缺少的是使用static auto bound = std::bind(fn2, std::ref(a), std::ref(b));它作为第四个选项。

4

2 回答 2

2

你有这个代码:

static auto bound = [&]{ fn2(a, b); };

分配仅在您第一次调用此函数时完成,因为它是static. 所以实际上它只被调用一次。当您制作 lambda 时,编译器会创建闭包,因此会捕获从第一次调用 fn1 时对 a 和 b 的引用。这是非常危险的。它可能会导致悬空引用。我很惊讶它没有崩溃,因为您正在从按值传递的函数参数关闭到局部变量。

我推荐这篇关于 lambdas 的优秀文章:http ://www.cprogramming.com/c++11/c++11-lambda-closures.html 。

于 2013-10-09T10:44:08.753 回答
0

作为一般规则,仅[&]当您的闭包将在当前范围结束时消失时才使用 lambdas。

如果它要超过当前范围,并且您需要按引用,请显式捕获您要捕获的内容,或者创建指向您要捕获的内容的本地指针并按值捕获它们。

在您的情况下,您的staticlambda 代码充满了未定义的行为,因为您[&]捕获ab在第一次调用中,然后在第二次调用中使用它。

理论上,编译器可以重写您的代码以捕获ab按值而不是按引用,然后每次都调用它,因为该实现与您编写的实现之间的唯一区别发生在行为未定义时,结果会很多快点。

它可以通过完全忽略您来完成更有效的工作static,因为在您第一次调用时离开范围后对象的整个状态static是未定义的,并且构造没有可见的副作用。

要解决 lambda 的问题,请使用[=]or[a,b]引入 lambda,它会按值捕获aand b。当我希望 lambda 比当前块持续更长时间时,我更喜欢在 lambdas 上显式捕获状态。

于 2013-10-16T15:24:22.513 回答