| @@ -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 | |||