提问人:Jeremy Friesner 提问时间:7/28/2023 最后编辑:Jeremy Friesner 更新时间:7/28/2023 访问量:59
将“const Whatever &”捕获到异步 lambda 中是否不安全?
Is capturing a `const Whatever &` into an asynchronous lambda unsafe?
问:
我有一些使用 lambda 的异步代码,我怀疑这有问题。问题的一个例子在这里(注意:伪代码,但真正的代码是基于JUCE的线程API):
// SUSPECT CODE (?)
void MessageReceived(const Message & msgRef) {
Threading(this).runAsync([&, msgRef] {
msgRef.Print(); // or whatever
});
}
特别是,我认为从 lambda 体内部使用是不安全的,因为虽然 lambda 机制复制了 ,但引用所引用的实际对象没有被复制,因此在异步 lambda 回调例程实际执行时很可能是一个悬空引用。msgRef
const Message &
Message
msgRef
我的问题是,我上面的推理正确吗?如果没有,我错过了什么?
另外,以下代码是否足以避免该问题?在本例中,我的函数创建对象的本地副本 (),而 lambda-callback 则引用该副本。我相信 lambda 捕获机制会制作自己的私有副本,当异步例程访问它时,保证它是有效的。localCopy
Message
localCopy
// FIXED CODE (?)
void MessageReceived(const Message & msgRef) {
Message localCopy = msgRef;
Threading(this).runAsync([&, localCopy] {
localCopy.Print(); // or whatever
});
}
答:
1赞
pptaszni
7/28/2023
#1
你的第一个简短例子是正确的。在默认的按引用捕获之后,您可以显式捕获按副本捕获 - 也就是说,lambda 保存引用对象的副本。msgRef
[expr.prim.lambda.捕获]
如果出现以下情况,则通过副本捕获实体
(10.2) — 使用非 this、& identifier 或 & identifier 形式的捕获显式捕获 初始 化。
(...)
如果实体是对对象的引用,则此类数据成员的类型是引用类型,如果实体是对函数的引用,则对引用的函数类型的左值引用,否则是相应捕获实体的类型。
后来标准给出了这个例子:
[&, i]{ }; // OK
这是假设在您的正文中,您没有任何自动变量,这些变量将默认捕获,然后在 lambda 正文中意外误用。MessageReceived
&
评论
msgRef
MessageReceived
runAsync
msgRef
MessageReceived()
MessageReceived()
msgRef
msgRef
localCopy
msgRef
localCopy
&