commit 80e10283657e0eb03883fefb41eb4c9c0585e7ad
parent 9df2f7f1a3b295bacf5a75f0c6cbc27845fe1a22
Author: falkTX <falktx@gmail.com>
Date: Fri, 25 Apr 2014 19:36:51 +0100
Add leakdetector class
Diffstat:
1 file changed, 139 insertions(+), 0 deletions(-)
diff --git a/distrho/extra/d_leakdetector.hpp b/distrho/extra/d_leakdetector.hpp
@@ -0,0 +1,139 @@
+/*
+ * DISTRHO Plugin Framework (DPF)
+ * Copyright (C) 2012-2014 Filipe Coelho <falktx@falktx.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any purpose with
+ * or without fee is hereby granted, provided that the above copyright notice and this
+ * permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
+ * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
+ * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef DISTRHO_LEAK_DETECTOR_HPP_INCLUDED
+#define DISTRHO_LEAK_DETECTOR_HPP_INCLUDED
+
+#include "../DistrhoUtils.hpp"
+
+// -----------------------------------------------------------------------
+// The following code was based from juce-core LeakDetector class
+// Copyright (C) 2013 Raw Material Software Ltd.
+
+/** A good old-fashioned C macro concatenation helper.
+ This combines two items (which may themselves be macros) into a single string,
+ avoiding the pitfalls of the ## macro operator.
+*/
+#define DISTRHO_JOIN_MACRO_HELPER(a, b) a ## b
+#define DISTRHO_JOIN_MACRO(item1, item2) DISTRHO_JOIN_MACRO_HELPER(item1, item2)
+
+/** This macro lets you embed a leak-detecting object inside a class.\n
+ To use it, simply declare a DISTRHO_LEAK_DETECTOR(YourClassName) inside a private section
+ of the class declaration. E.g.
+ \code
+ class MyClass
+ {
+ public:
+ MyClass();
+ void blahBlah();
+
+ private:
+ DISTRHO_LEAK_DETECTOR(MyClass)
+ };
+ \endcode
+*/
+#define DISTRHO_LEAK_DETECTOR(ClassName) \
+ friend class ::LeakedObjectDetector<ClassName>; \
+ static const char* getLeakedObjectClassName() noexcept { return #ClassName; } \
+ ::LeakedObjectDetector<ClassName> DISTRHO_JOIN_MACRO(leakDetector, __LINE__);
+
+#define DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(ClassName) \
+ DISTRHO_DECLARE_NON_COPY_CLASS(ClassName) \
+ DISTRHO_LEAK_DETECTOR(ClassName)
+
+//==============================================================================
+/**
+ Embedding an instance of this class inside another class can be used as a low-overhead
+ way of detecting leaked instances.
+
+ This class keeps an internal static count of the number of instances that are
+ active, so that when the app is shutdown and the static destructors are called,
+ it can check whether there are any left-over instances that may have been leaked.
+
+ To use it, use the DISTRHO_LEAK_DETECTOR macro as a simple way to put one in your
+ class declaration.
+*/
+template <class OwnerClass>
+class LeakedObjectDetector
+{
+public:
+ //==============================================================================
+ LeakedObjectDetector() noexcept { ++(getCounter().numObjects); }
+ LeakedObjectDetector(const LeakedObjectDetector&) noexcept { ++(getCounter().numObjects); }
+
+ ~LeakedObjectDetector() noexcept
+ {
+ if (--(getCounter().numObjects) < 0)
+ {
+ /** If you hit this, then you've managed to delete more instances of this class than you've
+ created.. That indicates that you're deleting some dangling pointers.
+
+ Note that although this assertion will have been triggered during a destructor, it might
+ not be this particular deletion that's at fault - the incorrect one may have happened
+ at an earlier point in the program, and simply not been detected until now.
+
+ Most errors like this are caused by using old-fashioned, non-RAII techniques for
+ your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
+ ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
+ */
+ d_stderr2("*** Dangling pointer deletion! Class: '%s', Count: %i", getLeakedObjectClassName(), getCounter().numObjects);
+ }
+ }
+
+private:
+ //==============================================================================
+ class LeakCounter
+ {
+ public:
+ LeakCounter() noexcept
+ {
+ numObjects = 0;
+ }
+
+ ~LeakCounter() noexcept
+ {
+ if (numObjects > 0)
+ {
+ /** If you hit this, then you've leaked one or more objects of the type specified by
+ the 'OwnerClass' template parameter - the name should have been printed by the line above.
+
+ If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for
+ your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays,
+ ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs!
+ */
+ d_stderr2("*** Leaked objects detected: %i instance(s) of class '%s'", numObjects, getLeakedObjectClassName());
+ }
+ }
+
+ // this should be an atomic...
+ volatile int numObjects;
+ };
+
+ static const char* getLeakedObjectClassName() noexcept
+ {
+ return OwnerClass::getLeakedObjectClassName();
+ }
+
+ static LeakCounter& getCounter() noexcept
+ {
+ static LeakCounter counter;
+ return counter;
+ }
+};
+
+// -----------------------------------------------------------------------
+
+#endif // DISTRHO_LEAK_DETECTOR_HPP_INCLUDED