I recently stumbled over this an I'm not sure about this. For g++ 10.5.0
the ctor of jthread
is (I omitted some details for better readability):
explicit
jthread(_Callable&& __f, _Args&&... __args)
: _M_thread{_S_create(_M_stop_source, std::forward<_Callable>(__f), std::forward<_Args>(__args)...)}
and
static thread
_S_create(stop_source& __ssrc, _Callable&& __f, _Args&&... __args)
{
if constexpr(is_invocable_v<decay_t<_Callable>, stop_token, decay_t<_Args>...>)
return thread{std::forward<_Callable>(__f), __ssrc.get_token(),
std::forward<_Args>(__args)...};
where __ssrc.get_token()
returns a std::stop_token
by value. Then we have the ctor of std::thread
:
explicit
thread(_Callable&& __f, _Args&&... __args)
{
auto __depend = ...
// A call wrapper holding tuple{DECAY_COPY(__f), DECAY_COPY(__args)...}
using _Invoker_type = _Invoker<__decayed_tuple<_Callable, _Args...>>;
_M_start_thread(_S_make_state<_Invoker_type>(
std::forward<_Callable>(__f), std::forward<_Args>(__args)...), _depend);
and
static _State_ptr
_S_make_state(_Args&&... __args)
{
using _Impl = _State_impl<_Callable>;
return _State_ptr{new _Impl{std::forward<_Args>(__args)...}};
and finally
_State_impl(_Args&&... __args)
: _M_func{{std::forward<_Args>(__args)...}}
So for me this looks like the stop token is forwarded to M_func
which is our initial void f
. If I interpret this correctly this would mean that we pass a temporary as reference to void f
which causes lifetime issues.
Do I understand this correctly?