继续这个问题:can-a-temperary-lambda-by-passed-by-reference?
我有一个固定的代码段:
// global variable
std::thread worker_thread;
// Template function
template <typename Functor>
void start_work(const Functor &worker_fn) // lambda passed by const ref
{
worker_thread = std::thread([&](){
worker_fn();
});
}
这就是这样的:
void do_work(int value)
{
printf("Hello from worker\r\n");
}
int main()
{
// This lambda is a temporary variable...
start_work([](int value){ do_work(value) });
}
这似乎有效,但我担心将临时lambda传递给线程构造函数,因为线程将运行,但函数start_work()将返回,temp-lambda将超出范围。
但是我正在查看定义的std :: thread构造函数:
thread()noexcept; (1)(自C ++ 11起)
线程(线程&amp;&amp; other)noexcept; (2)(自C ++ 11起)
模板&LT; class Function,class ... Args&gt; 显式线程(功能&amp;&amp; f,Args&amp;&amp; ... args); (3)(自C ++ 11起)
thread(const thread&amp;)= delete; (4)(自C ++ 11起)
所以我假设构造函数3被调用:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
我很难理解这里写的是什么,但看起来它会尝试移动lambda &&
,我认为这对于临时变量是好的。
我在我的代码片段中做了什么危险(即参考范围超出范围)或更正(即临时移动,一切都很好)?或两者都不是?
另一种方法是传递我的价值(制作副本),在这种情况下无论如何都不是那么糟糕。
答案 0 :(得分:8)
一个临时确实已被移动,但它是&#34;内部&#34;一,std::thread
的论点。
暂时持有&#34;外部&#34;临时,start_work
的参数,其生命周期在start_work
返回后结束。
因此,你的内心&#34; lambda对象持有对在执行期间可能存在或可能不存在的对象的引用,这是非常不安全的。
答案 1 :(得分:3)
lambda是C ++中的匿名struct
。如果我们要将片段翻译成没有lambdas的等效片段,那么它将成为
template <typename Functor>
void start_work(const Functor &worker_fn)
{
struct lambda {
const Functor& worker_fn;
auto operator()() const { worker_fn(); }
};
worker_thread = std::thread(lambda{worker_fn});
}
lambda
有一个非基于堆栈的const引用作为成员,只要start_work
返回,它就会悬挂,无论lambda
对象本身是否被复制。