关于lambda capture:
If the capture-default is &
, subsequent simple captures must not begin with &
.
struct S2 { void f(int i); };
void S2::f(int i)
{
[&]{}; // OK: by-reference capture default
[&, i]{}; // OK: by-reference capture, except i is captured by copy
[&, &i] {}; // Error: by-reference capture when by-reference is the default
[&, this] {}; // OK, equivalent to [&]
[&, this, i]{}; // OK, equivalent to [&, i]
}
If the capture-default is =
, subsequent simple captures must begin with &
or be *this
(since C++17) or this
(since C++20).
struct S2 { void f(int i); };
void S2::f(int i)
{
[=]{}; // OK: by-copy capture default
[=, &i]{}; // OK: by-copy capture, except i is captured by reference
[=, *this]{}; // until C++17: Error: invalid syntax
// since c++17: OK: captures the enclosing S2 by copy
[=, this] {}; // until C++20: Error: this when = is the default
// since C++20: OK, same as [=]
}
Any capture may appear only once:
struct S2 { void f(int i); };
void S2::f(int i)
{
[i, i] {}; // Error: i repeated
[this, *this] {}; // Error: "this" repeated (C++17)
}
如果lambda capture的是成员函数,这个lambda在它所capture的类对象释放后异步调用:
class A:
{
public:
int func()
{
std::ofstream myfile("example.txt");
if (myfile.is_open())
{
myfile << "Write from child thread.\n";
myfile.close();
}
else
{
std::cout << "Unable to open file";
}
}
void detach()
{
std::thread t([this]() {
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
func();
});
t.detach();
}
};
int main()
{
{
A a;
a.detach();
}
std::cout << "main end" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
return 0;
}
当main函数执行到打印“main end”时,a对象已经释放,但是它创建的子线程中调用了它的成员函数依然可以正常执行。这是因为成员函数在转变为汇编代码时与普通的函数一样,只不过会将this指针作为它的第一个参数传入,而且a对象的func()方法中没有调用A的其他成员变量,因此不会发生crash。正确的写法应该是在进入lambda的时候判断此时它capture的this指针所指向的对象是否还是有效的:
#define RETURN_FROM_LAMBDA_IF_DEAD(x) \
auto sharedThis = x.lock(); \
if(!sharedThis) \
return;
class A: public std::enable_shared_from_this<A>
{
public:
int func()
{
std::ofstream myfile("example.txt");
if (myfile.is_open())
{
myfile << "Write from child thread.\n";
myfile.close();
}
else
{
std::cout << "Unable to open file";
}
}
void detach()
{
std::thread t([weakThis = weak_from_this(), this]() {
RETURN_FROM_LAMBDA_IF_DEAD(weakThis);
std::this_thread::sleep_for(std::chrono::milliseconds(3000));
func();
});
t.detach();
}
};
int main()
{
{
A a;
a.detach();
}
std::cout << "main end" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
return 0;
}
另外,如果确实想要在lambda中调用this指向对象的成员函数且这个成员函数没有调用成员变量,可以把这个成员函数定义成private static,这样就不会有上面说的问题。
参考链接: