關於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,這樣就不會有上面說的問題。
參考鏈接: