Home > Software engineering >  Capturing shared_ptr in lambda using std::move
Capturing shared_ptr in lambda using std::move

Time:09-21

In following code std::move in lambda capture list felt unnecessary to me, but compiler does seem to need it.

As there is extra code for copying shared_ptr is generated if I don't use std::move.

Question is, why compiler can't optimise this on its own.

template<typename T>
std::function<void(void)> prepLambdaImpl(std::shared_ptr<T> aptr) {
#ifdef CONVERT_SHARED_PTR_TO_XVALUE
  return [aptr=std::move(aptr)]
#else
  return [aptr]
#endif
  {
      printf("use count: %ld\n", aptr.use_count());
  };
}

Working example: https://godbolt.org/z/W3oWEjsjK

CodePudding user response:

Without std::move the std::shared_ptr will be copied into the lambda. Copying (but not moving) a std::shared_ptr requires incrementing its atomic reference count (and decrementing it again once the copy is destroyed).

In theory a compiler would be allowed to remove the atomic increment from the copy and the atomic decrement from the aptr parameter's destructor since they cancel, assuming it makes sure that no other thread can observe an intermediate state, however compilers tend to be conservative and don't optimize atomic operations because that is often not what users except to happen.

CodePudding user response:

Automatic move only happens in return statement in some specific circumstances, which are not met here.

Last usage doesn't trigger a move instead of a copy.

The as-if rule allows optimization as long than observable behaviour is unchanged. Whereas we know the 2 forms are equivalent, it is not easy to know. Especially move and copy are unrelated functions; so optimizers only uses the copy code to try to optimize it (and it probably misses some extra information as invariant of the class (as refcounter not 0 at start of function)).

  • Related