lambda 函数 capture by reference 很好理解,就类似于 Functor, 会在 closure 中定义一些指针指向使用的对象地址。
然后 capture by value 通常也类似 Functor,会在 closure 中定义一些对象,然后将使用到的对象复制进 closure 中.
需要注意一点的是:
One other thing that is sometimes overlooked however, is that even when one uses a capture-by-value-lambda in a member function, it doesn’t create a copy of the used member variables, but only makes a copy of the this pointer.
所以,如果在类成员函数中使用 lambda 函数,而且是 capture by value, 那么其结果就是: 该 lambda 函数对一个类的成员变量 capture by this pointer, 也就是 capture by reference,而对一个类 非成员变量 则 capture by value.
例如:
#include <iostream>
#include <vector>
using namespace std;
struct Foo
{
int a;
std::vector<int> b;
};
class Test
{
Foo foo;
public:
void func()
{
int c = 10;
Foo f;
cout << "Out address of a(member): " << &foo.a << endl;
cout << "Out address of b(menber): " << &foo.b << endl;
cout << "Out address of c(non-member): " << &c << endl;
cout << "Out address of d(non-member): " << &f << endl;
auto lambda = [=]()
{
cout << "In address of a(member): " << &foo.a << endl;
cout << "In address of b(menber): " << &foo.b << endl;
cout << "In address of b(non-member): " << &c << endl;
cout << "In address of d(non-member): " << &f << endl;
};
lambda();
}
};
int main()
{
Test t;
t.func();
cout << "Out address of t: " << &t << endl;
auto lambda = [=]()
{
cout << "In address of t: " << &t << endl;
};
lambda();
return 0;
}
运行结果:
$g++ -std=c++11 -o main *.cpp
$main
Out address of a(member): 0x7fffedde7430 // 在 lambda 函数外成员地址
Out address of b(menber): 0x7fffedde7438
Out address of c(non-member): 0x7fffedde73ec // 在 lambda 函数外 非 成员地址
Out address of d(non-member): 0x7fffedde73c0
In address of a(member): 0x7fffedde7430 // 在 lambda 函数内成员地址(与lambda外地址相同,by reference)
In address of b(menber): 0x7fffedde7438
In address of b(non-member): 0x7fffedde7398 // 在 lambda 函数内 非 成员地址(与lambda外地址不同, by value)
In address of d(non-member): 0x7fffedde73a0
Out address of t: 0x7fffedde7430
In address of t: 0x7fffedde7410
除了上面那个点,下面两个例子也需要特殊注意
e.g 1:
在 lambda 本体中删除该 instance 类似于在 class 成员函数中删除 this 指针。如果在 lambda 函数中删除自身,然后再去获取 capture by value
变量,会导致程序崩溃。(同理,需要注意 lambda 函数 capture by value 自身 shared_ptr 而导致循环引用的问题)
#include <iostream>
#include <memory>
#include <functional>
using namespace std;
int main()
{
std::function<int(void)> func;
int i = 2;
int c = 5;
{
func = [=,&func,&i]() {
int b =3;
func = nullptr; // here will destory the std::function
i+=1;
return i+b; // i+b+c segment fault
};
}
cout << "Hello World: " << func() << endl;
return 0;
}
e.g.2:
lambda 内的 static
变量被该 lambda 的所有 instance 共享;因为本质上 lambda 是一个class, 一个 class的所有对象共享其 static 变量;不要误以为每一个 lambda 都独享一份自己的static变量哈,这是错误的。
#include <iostream>
#include <vector>
#include <algorithm>
using std::cout;
void some_function()
{
std::vector<int> v = {0,1,2,3,4,5};
std::for_each( v.begin(), v.end(),
[](const int &i)
{
static int calls_to_cout = 0;
cout << "cout has been called " << calls_to_cout << " times.\n"
<< "\tCurrent int: " << i << "\n";
++calls_to_cout;
} );
}
int main()
{
some_function();
some_function();
}