将对 temporary/annonymous lambda 的常量引用传递给 std::thread 构造函数是否安全?
Is it safe to pass const reference to temporary/annonymous lambda into std::thread constructor?
从这个问题开始:
我有一个固定的代码片段:
// 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() 将 return 并且temp-lambda 将超出范围。
但是我正在查看定义的 std::thread 构造函数:
thread() noexcept; (1) (since C++11)
thread( thread&& other ) noexcept; (2) (since C++11)
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args ); (3) (since C++11)
thread(const thread&) = delete; (4) (since C++11)
所以我假设构造函数 3 被调用:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
我很难理解这里写的是什么,但看起来它会尝试移动 lambda &&
,我认为这对于临时变量是可以的。
那么我在我的代码片段中所做的是危险的(即引用超出范围)还是正确的(即温度被移动并且一切正常)?或者两者都不是??
另一种方法是只传递我的值(制作副本),在这种情况下这还算不错。
lambda 是 C++ 中的匿名 struct
。如果我们要将片段翻译成没有 lambda 的等效片段,它将变成
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
returns 时悬挂,不管 lambda
对象本身是否已复制。
A 临时文件确实被移动了,但它是 "inner" 临时文件,std::thread
的参数。
该临时文件持有对 "outer" 临时文件的引用,start_work
的参数,其生命周期在 start_work
返回后结束。
因此,您的 "inner" lambda 对象持有对执行期间可能存在或不存在的对象的引用,这是非常不安全的。
从这个问题开始:
我有一个固定的代码片段:
// 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() 将 return 并且temp-lambda 将超出范围。
但是我正在查看定义的 std::thread 构造函数:
thread() noexcept; (1) (since C++11)
thread( thread&& other ) noexcept; (2) (since C++11)
template< class Function, class... Args > explicit thread( Function&& f, Args&&... args ); (3) (since C++11)
thread(const thread&) = delete; (4) (since C++11)
所以我假设构造函数 3 被调用:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
我很难理解这里写的是什么,但看起来它会尝试移动 lambda &&
,我认为这对于临时变量是可以的。
那么我在我的代码片段中所做的是危险的(即引用超出范围)还是正确的(即温度被移动并且一切正常)?或者两者都不是??
另一种方法是只传递我的值(制作副本),在这种情况下这还算不错。
lambda 是 C++ 中的匿名 struct
。如果我们要将片段翻译成没有 lambda 的等效片段,它将变成
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
returns 时悬挂,不管 lambda
对象本身是否已复制。
A 临时文件确实被移动了,但它是 "inner" 临时文件,std::thread
的参数。
该临时文件持有对 "outer" 临时文件的引用,start_work
的参数,其生命周期在 start_work
返回后结束。
因此,您的 "inner" lambda 对象持有对执行期间可能存在或不存在的对象的引用,这是非常不安全的。