From 4fffde234c34dcc7f3fc6deba376dc64966d3b97 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 11 May 2014 23:50:28 +0100 Subject: [PATCH] Add scoped pointer class; use it on some widget classes --- dgl/Base.hpp | 1 + dgl/ImageButton.hpp | 2 + dgl/ImageKnob.hpp | 2 + dgl/ImageSlider.hpp | 2 + distrho/extra/d_leakdetector.hpp | 2 +- distrho/extra/d_scopedpointer.hpp | 235 ++++++++++++++++++++++++++++++ 6 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 distrho/extra/d_scopedpointer.hpp diff --git a/dgl/Base.hpp b/dgl/Base.hpp index dcb91f36..fdb71449 100644 --- a/dgl/Base.hpp +++ b/dgl/Base.hpp @@ -18,6 +18,7 @@ #define DGL_BASE_HPP_INCLUDED #include "../distrho/extra/d_leakdetector.hpp" +#include "../distrho/extra/d_scopedpointer.hpp" // ----------------------------------------------------------------------- // Define namespace diff --git a/dgl/ImageButton.hpp b/dgl/ImageButton.hpp index f61c874a..781250a7 100644 --- a/dgl/ImageButton.hpp +++ b/dgl/ImageButton.hpp @@ -59,6 +59,8 @@ private: DISTRHO_LEAK_DETECTOR(ImageButton) }; +typedef ScopedPointer ImageButtonPtr; + // ----------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/dgl/ImageKnob.hpp b/dgl/ImageKnob.hpp index 83bd2d52..47fe3560 100644 --- a/dgl/ImageKnob.hpp +++ b/dgl/ImageKnob.hpp @@ -87,6 +87,8 @@ private: DISTRHO_LEAK_DETECTOR(ImageKnob) }; +typedef ScopedPointer ImageKnobPtr; + // ----------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/dgl/ImageSlider.hpp b/dgl/ImageSlider.hpp index 31a26fc9..c9b4823c 100644 --- a/dgl/ImageSlider.hpp +++ b/dgl/ImageSlider.hpp @@ -83,6 +83,8 @@ private: DISTRHO_LEAK_DETECTOR(ImageSlider) }; +typedef ScopedPointer ImageSliderPtr; + // ----------------------------------------------------------------------- END_NAMESPACE_DGL diff --git a/distrho/extra/d_leakdetector.hpp b/distrho/extra/d_leakdetector.hpp index 74eb97a8..ede4db9f 100644 --- a/distrho/extra/d_leakdetector.hpp +++ b/distrho/extra/d_leakdetector.hpp @@ -66,7 +66,7 @@ To use it, use the DISTRHO_LEAK_DETECTOR macro as a simple way to put one in your class declaration. */ -template +template class DistrhoLeakedObjectDetector { public: diff --git a/distrho/extra/d_scopedpointer.hpp b/distrho/extra/d_scopedpointer.hpp new file mode 100644 index 00000000..609df6b6 --- /dev/null +++ b/distrho/extra/d_scopedpointer.hpp @@ -0,0 +1,235 @@ +/* + * DISTRHO Plugin Framework (DPF) + * Copyright (C) 2012-2014 Filipe Coelho + * + * 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_SCOPED_POINTER_HPP_INCLUDED +#define DISTRHO_SCOPED_POINTER_HPP_INCLUDED + +#include "../DistrhoUtils.hpp" + +// ----------------------------------------------------------------------- +// The following code was based from juce-core ScopedPointer class +// Copyright (C) 2013 Raw Material Software Ltd. + +/** + Used by container classes as an indirect way to delete an object of a + particular type. + + The generic implementation of this class simply calls 'delete', but you can + create a specialised version of it for a particular class if you need to + delete that type of object in a more appropriate way. +*/ +template +struct ContainerDeletePolicy +{ + static void destroy(ObjectType* const object) + { + delete object; + } +}; + +//============================================================================== +/** + This class holds a pointer which is automatically deleted when this object goes + out of scope. + + Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer + gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or + as member variables is a good way to use RAII to avoid accidentally leaking dynamically + created objects. + + A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer + to an object. If you use the assignment operator to assign a different object to a + ScopedPointer, the old one will be automatically deleted. + + A const ScopedPointer is guaranteed not to lose ownership of its object or change the + object to which it points during its lifetime. This means that making a copy of a const + ScopedPointer is impossible, as that would involve the new copy taking ownership from the + old one. + + If you need to get a pointer out of a ScopedPointer without it being deleted, you + can use the release() method. + + Something to note is the main difference between this class and the std::auto_ptr class, + which is that ScopedPointer provides a cast-to-object operator, wheras std::auto_ptr + requires that you always call get() to retrieve the pointer. The advantages of providing + the cast is that you don't need to call get(), so can use the ScopedPointer in pretty much + exactly the same way as a raw pointer. The disadvantage is that the compiler is free to + use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult + to return a ScopedPointer as the result of a function. To avoid this causing errors, + ScopedPointer contains an overloaded constructor that should cause a syntax error in these + circumstances, but it does mean that instead of returning a ScopedPointer from a function, + you'd need to return a raw pointer (or use a std::auto_ptr instead). +*/ +template +class ScopedPointer +{ +public: + //============================================================================== + /** Creates a ScopedPointer containing a null pointer. */ + ScopedPointer() noexcept + : object(nullptr) {} + + /** Creates a ScopedPointer that owns the specified object. */ + ScopedPointer(ObjectType* const objectToTakePossessionOf) noexcept + : object(objectToTakePossessionOf) {} + + /** Creates a ScopedPointer that takes its pointer from another ScopedPointer. + + Because a pointer can only belong to one ScopedPointer, this transfers + the pointer from the other object to this one, and the other object is reset to + be a null pointer. + */ + ScopedPointer(ScopedPointer& objectToTransferFrom) noexcept + : object(objectToTransferFrom.object) + { + objectToTransferFrom.object = nullptr; + } + + /** Destructor. + This will delete the object that this ScopedPointer currently refers to. + */ + ~ScopedPointer() + { + ContainerDeletePolicy::destroy(object); + } + + /** Changes this ScopedPointer to point to a new object. + + Because a pointer can only belong to one ScopedPointer, this transfers + the pointer from the other object to this one, and the other object is reset to + be a null pointer. + + If this ScopedPointer already points to an object, that object + will first be deleted. + */ + ScopedPointer& operator=(ScopedPointer& objectToTransferFrom) + { + if (this != objectToTransferFrom.getAddress()) + { + // Two ScopedPointers should never be able to refer to the same object - if + // this happens, you must have done something dodgy! + DISTRHO_SAFE_ASSERT_RETURN(object == nullptr || object != objectToTransferFrom.object, *this); + + ObjectType* const oldObject = object; + object = objectToTransferFrom.object; + objectToTransferFrom.object = nullptr; + ContainerDeletePolicy::destroy(oldObject); + } + + return *this; + } + + /** Changes this ScopedPointer to point to a new object. + + If this ScopedPointer already points to an object, that object + will first be deleted. + + The pointer that you pass in may be a nullptr. + */ + ScopedPointer& operator=(ObjectType* const newObjectToTakePossessionOf) + { + if (object != newObjectToTakePossessionOf) + { + ObjectType* const oldObject = object; + object = newObjectToTakePossessionOf; + ContainerDeletePolicy::destroy(oldObject); + } + + return *this; + } + + //============================================================================== + /** Returns the object that this ScopedPointer refers to. */ + operator ObjectType*() const noexcept { return object; } + + /** Returns the object that this ScopedPointer refers to. */ + ObjectType* get() const noexcept { return object; } + + /** Returns the object that this ScopedPointer refers to. */ + ObjectType& operator*() const noexcept { return *object; } + + /** Lets you access methods and properties of the object that this ScopedPointer refers to. */ + ObjectType* operator->() const noexcept { return object; } + + //============================================================================== + /** Removes the current object from this ScopedPointer without deleting it. + This will return the current object, and set the ScopedPointer to a null pointer. + */ + ObjectType* release() noexcept { ObjectType* const o = object; object = nullptr; return o; } + + //============================================================================== + /** Swaps this object with that of another ScopedPointer. + The two objects simply exchange their pointers. + */ + void swapWith(ScopedPointer& other) noexcept + { + // Two ScopedPointers should never be able to refer to the same object - if + // this happens, you must have done something dodgy! + DISTRHO_SAFE_ASSERT_RETURN(object != other.object && this != other.getAddress(),); + + std::swap(object, other.object); + } + +private: + //============================================================================== + ObjectType* object; + + // (Required as an alternative to the overloaded & operator). + const ScopedPointer* getAddress() const noexcept { return this; } + +#ifndef _MSC_VER // (MSVC can't deal with multiple copy constructors) + /* The copy constructors are private to stop people accidentally copying a const ScopedPointer + (the compiler would let you do so by implicitly casting the source to its raw object pointer). + + A side effect of this is that in a compiler that doesn't support C++11, you may hit an + error when you write something like this: + + ScopedPointer m = new MyClass(); // Compile error: copy constructor is private. + + Even though the compiler would normally ignore the assignment here, it can't do so when the + copy constructor is private. It's very easy to fix though - just write it like this: + + ScopedPointer m (new MyClass()); // Compiles OK + + It's probably best to use the latter form when writing your object declarations anyway, as + this is a better representation of the code that you actually want the compiler to produce. + */ + DISTRHO_DECLARE_NON_COPY_CLASS(ScopedPointer); +#endif +}; + +//============================================================================== +/** Compares a ScopedPointer with another pointer. + This can be handy for checking whether this is a null pointer. +*/ +template +bool operator==(const ScopedPointer& pointer1, ObjectType* const pointer2) noexcept +{ + return static_cast(pointer1) == pointer2; +} + +/** Compares a ScopedPointer with another pointer. + This can be handy for checking whether this is a null pointer. +*/ +template +bool operator!=(const ScopedPointer& pointer1, ObjectType* const pointer2) noexcept +{ + return static_cast(pointer1) != pointer2; +} + +// ----------------------------------------------------------------------- + +#endif // DISTRHO_SCOPED_POINTER_HPP_INCLUDED