Lambda argument that steals unique_ptr used to do the call
02:44 04 Feb 2026

In this code:

#include 
#include 
struct A {
  A() { std::cout << "A::A(), this: " << this << std::endl; }
  void call(auto lambda) const {
    std::cout << "A::call() this: " << this << std::endl;
    lambda();
  }
};

int main() {
  auto p{std::make_unique()};
  p->call([p2 = std::move(p)] { std::cout << "From lambda" << std::endl; });
  return 0;
}

I would assume that p->call(...) would dereference a nullpointer because the capture [p2 = std::move(p)] must be executed before the call and after the lambda has been constructed, p is set to null according to std::unique_ptr's move constructor (5) in https://en.cppreference.com/w/cpp/memory/unique_ptr/unique_ptr.html

Constructs a unique_ptr by transferring ownership from u to *this and stores the null pointer in u

But somehow it seems that first the unique_ptr is dereferenced, the address temporarily saved, then the lambda is constructed and then A::call is called on the temporary address that was saved before the resources of p have been stolen by p2 during lambda construction.

Why is that and where can I read this up?

Output with valgrind shows no errors:

valgrind --leak-check=full  --track-origins=yes ./main
==841554== Memcheck, a memory error detector
==841554== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==841554== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==841554== Command: ./main
==841554== 
A::A(), this: 0x4e4b080
A::call() this: 0x4e4b080
From lambda
==841554== 
==841554== HEAP SUMMARY:
==841554==     in use at exit: 0 bytes in 0 blocks
==841554==   total heap usage: 3 allocs, 3 frees, 74,753 bytes allocated
==841554== 
==841554== All heap blocks were freed -- no leaks are possible
==841554== 
==841554== For lists of detected and suppressed errors, rerun with: -s
==841554== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
c++