79491807

Date: 2025-03-07 09:35:11
Score: 1
Natty:
Report link

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?

Reasons:
  • Long answer (-1):
  • Has code block (-0.5):
  • Ends in question mark (2):
  • Low reputation (0.5):
Posted by: jawa