FR: Reference counting for listeners

I just spent a bunch of time trying to track down a dangling listener. It would be really nice if juce automatically managed the listener connection so it would be impossible, kind of like Qt’s signals / slots. But I’m guessing that a pretty major API change.

Instead, how about something like this (in debug builds only):

diff --git a/modules/juce_data_structures/values/juce_ValueTree.cpp b/modules/juce_data_structures/values/juce_ValueTree.cpp
index e185d8d81..7675e1ed4 100644
--- a/modules/juce_data_structures/values/juce_ValueTree.cpp
+++ b/modules/juce_data_structures/values/juce_ValueTree.cpp
@@ -638,7 +638,10 @@ ValueTree::ValueTree (ValueTree&& other) noexcept
 }
 
 ValueTree::~ValueTree()
-{
+{
+    for (int i = 0; i < listeners.size(); i++)
+        listeners.getListeners().getUnchecked (i)->count--;
+    
     if (! listeners.isEmpty() && object != nullptr)
         object->valueTreesWithListeners.removeValue (this);
 }
@@ -969,7 +972,10 @@ void ValueTree::reorderChildren (const OwnedArray<ValueTree>& newOrder, UndoMana
 void ValueTree::addListener (Listener* listener)
 {
     if (listener != nullptr)
-    {
+    {
+        if (! listeners.getListeners().contains (listener))
+            listener->count++;
+        
         if (listeners.isEmpty() && object != nullptr)
             object->valueTreesWithListeners.add (this);
 
@@ -978,9 +984,12 @@ void ValueTree::addListener (Listener* listener)
 }
 
 void ValueTree::removeListener (Listener* listener)
-{
-    listeners.remove (listener);
+{
+    if (listeners.getListeners().contains (listener))
+        listener->count--;
 
+    listeners.remove (listener);
+    
     if (listeners.isEmpty() && object != nullptr)
         object->valueTreesWithListeners.removeValue (this);
 }
diff --git a/modules/juce_data_structures/values/juce_ValueTree.h b/modules/juce_data_structures/values/juce_ValueTree.h
index 1145a68ae..652391d54 100644
--- a/modules/juce_data_structures/values/juce_ValueTree.h
+++ b/modules/juce_data_structures/values/juce_ValueTree.h
@@ -481,8 +481,13 @@ public:
     {
     public:
         /** Destructor. */
-        virtual ~Listener() = default;
-
+        virtual ~Listener()
+        {
+            jassert (count == 0);
+        }
+
+        int count = 0;
+        
         /** This method is called when a property of this tree (or of one of its sub-trees) is changed.
             Note that when you register a listener to a tree, it will receive this callback for
             property changes in that tree, and also for any of its children, (recursively, at any depth).

I added this and it tracked down my listener leak in < 10 seconds.

I believe LookAndFeel has something like this.