Why don't you just use smart pointers as you mentioned?
#include <functional>
#include <memory>
#include <iostream>
struct Foo{
    Foo() {
        std::cout << "Foo created" << std::endl;
    }
    ~Foo() {
        std::cout << "Foo destroyed" << std::endl;
    }
    int i = 0;
    void addInt(int input){
        i += input;
    }
};
int main(int argc, char* args[]){
    std::cout << "-- Start of program" << std::endl;
    std::shared_ptr<Foo> lostMemory( new Foo() );
    std::weak_ptr<Foo> weak = lostMemory;
    std::cout << "-- Before lambda" << std::endl;
    std::function<void(int)> lambda = [weak](int b) { 
        if ( auto sp = weak.lock() ) { 
            std::cout << "Added int" << std::endl;
            sp->addInt(b);
        } 
        else std::cout << "Not doing this" << std::endl;
    };
    std::cout << "-- After lambda" << std::endl;
    lambda(8);
    std::cout << "-- Before deleting" << std::endl;
    lostMemory.reset();
    std::cout << "-- After lambda" << std::endl;
    lambda(8);
    std::cout << "-- The end" << std::endl;
    return 0;
}
Produces
Program stdout
-- Start of program
Foo created
-- Before lambda
-- After lambda
Added int
-- Before deleting
Foo destroyed
-- After lambda
Not doing this
-- The end
Godbolt link: https://godbolt.org/z/ceMevznhv
See, lambdas are mere anonymous functors under the hood. If you paste the above code on cppinsights.io you will have something like this (cleaned up a bit):
#include <functional>
#include <memory>
struct Foo
{
  int i = 0;
  inline void addInt(int input)
  {
    this->i = this->i + input;
  }
};
int main(int argc, char ** args)
{
  std::shared_ptr<Foo> lostMemory = std::shared_ptr<Foo>(new Foo());
    
  class __lambda_13_39
  {
    public: 
    inline /*constexpr */ void operator()(int b) const
    {
      static_cast<const std::__shared_ptr_access<Foo, 2, false, false>&>(lostMemory).operator->()->addInt(b);
    }
    
    private: 
    std::shared_ptr<Foo> lostMemory;
    public: 
    __lambda_13_39(const std::shared_ptr<Foo> & _lostMemory)
    : lostMemory{_lostMemory}
    {}
    
  };
  
  std::function<void (int)> lambda = std::function<void (int)>(__lambda_13_39{lostMemory});
  lambda.operator()(8);
  static_cast<std::__shared_ptr<Foo, 2>&>(lostMemory).reset();
  lambda.operator()(8);
  return 0;
}
You can see that the functor holds an std::shared_ptr<Foo> as a member. That is exactly what the lambda will do as well.
Alternatively, use a functor itself instead of a lambda for cases that are a bit more evolving.