Basic idea is to use a Class, with static methods to add and remove references in a static vector, that keeps track of these references, and check that vector upon exit.

The class is detecting intentional leaks that I create, but maybe you can find a case where it does not detect the leak, that I am not seeing

 
 void checkLeakStack();
 class LeakDbg
 {
 private:
 LeakDbg()
 {
 /// Constructor will only be called once,
 /// since it's a singlton class
 std::atexit( checkLeakStack );
 }

 public:
 struct Pair
 {
 std::string name;
 void* ref;
 bool operator==( const Pair &other ) const { return ref == other.ref; }

 };
 static bool locked;
 static std::vector<Pair> stack;
 static LeakDbg& instance()
 {
 static LeakDbg INSTANCE;
 return INSTANCE;
 }

 static void addRef(const std::string& nm, void* ptr)
 {
 stack.push_back(Pair{ nm, ptr });
 }
 static void remRef(void* ptr)
 {
 /// If it's not enabled, it means
 /// it's OK to remove a ref
 if( !LeakDbg::locked ){
 Pair search = Pair{"",ptr};
 std::vector<Pair> vect;
 // std::remove(vect.begin(), vect.end(), search);
 stack.erase(std::remove(stack.begin(), stack.end(), search), stack.end());
 }
 }

 };


 bool LeakDbg::locked = false;
 std::vector<LeakDbg::Pair> LeakDbg::stack = std::vector<LeakDbg::Pair>();

 void checkLeakStack()
 {
 /// Here the stack should be emoty
 /// you can print or assert if the stack is not empty
 std::cout << "There are " << LeakDbg::stack.size() << " leaks ..." "\n";
 for ( LeakDbg::Pair pair : LeakDbg::stack) {
 const std::string msg = pair.name + " is leaked";
 std::cout << msg << std::endl;
 }
 }

Add defines

 #define ADD_LEAK(msg, ptr) LeakDbg::addRef(msg, ptr);
 #define REM_LEAK(ptr) LeakDbg::remRef(ptr);
 #define CREATE_LEAK_DET() LeakDbg::instance();
 #define LCK_LEAK_DET(st) LeakDbg::locked = st;

 // ADD_LEAK -> Add it in a class constructor
 // REM_LEAK -> Add it in a class destructor
 // CREATE_LEAK_DET -> Call it once to make sure "std::atexit" is called
 // LCK_LEAK_DET -> If set to "true", all objects destructed after,
 // -> will be considered a leak

Test


 struct Test {
 Test() {
 ADD_LEAK( "Cls", this )
 }
 ~Test() {
 REM_LEAK( this )
 }

 };


 int main() {
 CREATE_LEAK_DET()
 Test *obj1 = new Test();
 Test *obj2 = new Test();
 Test *obj3 = new Test();
 delete obj2;
 LCK_LEAK_DET( true )
 }