ScopedPointer.hpp (10776B)
1 /* 2 * DISTRHO Plugin Framework (DPF) 3 * Copyright (C) 2012-2016 Filipe Coelho <falktx@falktx.com> 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any purpose with 6 * or without fee is hereby granted, provided that the above copyright notice and this 7 * permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD 10 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN 11 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 13 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #ifndef DISTRHO_SCOPED_POINTER_HPP_INCLUDED 18 #define DISTRHO_SCOPED_POINTER_HPP_INCLUDED 19 20 #include "../DistrhoUtils.hpp" 21 22 #include <algorithm> 23 24 START_NAMESPACE_DISTRHO 25 26 // ----------------------------------------------------------------------- 27 // The following code was based from juce-core ScopedPointer class 28 29 /** 30 Copyright (C) 2013 Raw Material Software Ltd. 31 32 Permission is granted to use this software under the terms of the ISC license 33 http://www.isc.org/downloads/software-support-policy/isc-license/ 34 35 Permission to use, copy, modify, and/or distribute this software for any 36 purpose with or without fee is hereby granted, provided that the above 37 copyright notice and this permission notice appear in all copies. 38 39 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD 40 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND 41 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, 42 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 43 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 44 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 45 OF THIS SOFTWARE. 46 */ 47 48 //============================================================================== 49 /** 50 This class holds a pointer which is automatically deleted when this object goes 51 out of scope. 52 53 Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer 54 gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or 55 as member variables is a good way to use RAII to avoid accidentally leaking dynamically 56 created objects. 57 58 A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer 59 to an object. If you use the assignment operator to assign a different object to a 60 ScopedPointer, the old one will be automatically deleted. 61 62 A const ScopedPointer is guaranteed not to lose ownership of its object or change the 63 object to which it points during its lifetime. This means that making a copy of a const 64 ScopedPointer is impossible, as that would involve the new copy taking ownership from the 65 old one. 66 67 If you need to get a pointer out of a ScopedPointer without it being deleted, you 68 can use the release() method. 69 70 Something to note is the main difference between this class and the std::auto_ptr class, 71 which is that ScopedPointer provides a cast-to-object operator, wheras std::auto_ptr 72 requires that you always call get() to retrieve the pointer. The advantages of providing 73 the cast is that you don't need to call get(), so can use the ScopedPointer in pretty much 74 exactly the same way as a raw pointer. The disadvantage is that the compiler is free to 75 use the cast in unexpected and sometimes dangerous ways - in particular, it becomes difficult 76 to return a ScopedPointer as the result of a function. To avoid this causing errors, 77 ScopedPointer contains an overloaded constructor that should cause a syntax error in these 78 circumstances, but it does mean that instead of returning a ScopedPointer from a function, 79 you'd need to return a raw pointer (or use a std::auto_ptr instead). 80 */ 81 template<class ObjectType> 82 class ScopedPointer 83 { 84 public: 85 //============================================================================== 86 /** Creates a ScopedPointer containing a null pointer. */ 87 ScopedPointer() noexcept 88 : object(nullptr) {} 89 90 /** Creates a ScopedPointer that owns the specified object. */ 91 ScopedPointer(ObjectType* const objectToTakePossessionOf) noexcept 92 : object(objectToTakePossessionOf) {} 93 94 /** Creates a ScopedPointer that takes its pointer from another ScopedPointer. 95 96 Because a pointer can only belong to one ScopedPointer, this transfers 97 the pointer from the other object to this one, and the other object is reset to 98 be a null pointer. 99 */ 100 ScopedPointer(ScopedPointer& objectToTransferFrom) noexcept 101 : object(objectToTransferFrom.object) 102 { 103 objectToTransferFrom.object = nullptr; 104 } 105 106 /** Destructor. 107 This will delete the object that this ScopedPointer currently refers to. 108 */ 109 ~ScopedPointer() 110 { 111 delete object; 112 } 113 114 /** Changes this ScopedPointer to point to a new object. 115 116 Because a pointer can only belong to one ScopedPointer, this transfers 117 the pointer from the other object to this one, and the other object is reset to 118 be a null pointer. 119 120 If this ScopedPointer already points to an object, that object 121 will first be deleted. 122 */ 123 ScopedPointer& operator=(ScopedPointer& objectToTransferFrom) 124 { 125 if (this != objectToTransferFrom.getAddress()) 126 { 127 // Two ScopedPointers should never be able to refer to the same object - if 128 // this happens, you must have done something dodgy! 129 DISTRHO_SAFE_ASSERT_RETURN(object == nullptr || object != objectToTransferFrom.object, *this); 130 131 ObjectType* const oldObject = object; 132 object = objectToTransferFrom.object; 133 objectToTransferFrom.object = nullptr; 134 delete oldObject; 135 } 136 137 return *this; 138 } 139 140 /** Changes this ScopedPointer to point to a new object. 141 142 If this ScopedPointer already points to an object, that object 143 will first be deleted. 144 145 The pointer that you pass in may be a nullptr. 146 */ 147 ScopedPointer& operator=(ObjectType* const newObjectToTakePossessionOf) 148 { 149 if (object != newObjectToTakePossessionOf) 150 { 151 ObjectType* const oldObject = object; 152 object = newObjectToTakePossessionOf; 153 delete oldObject; 154 } 155 156 return *this; 157 } 158 159 //============================================================================== 160 /** Returns the object that this ScopedPointer refers to. */ 161 operator ObjectType*() const noexcept { return object; } 162 163 /** Returns the object that this ScopedPointer refers to. */ 164 ObjectType* get() const noexcept { return object; } 165 166 /** Returns the object that this ScopedPointer refers to. */ 167 ObjectType& getObject() const noexcept { return *object; } 168 169 /** Returns the object that this ScopedPointer refers to. */ 170 ObjectType& operator*() const noexcept { return *object; } 171 172 /** Lets you access methods and properties of the object that this ScopedPointer refers to. */ 173 ObjectType* operator->() const noexcept { return object; } 174 175 //============================================================================== 176 /** Removes the current object from this ScopedPointer without deleting it. 177 This will return the current object, and set the ScopedPointer to a null pointer. 178 */ 179 ObjectType* release() noexcept { ObjectType* const o = object; object = nullptr; return o; } 180 181 //============================================================================== 182 /** Swaps this object with that of another ScopedPointer. 183 The two objects simply exchange their pointers. 184 */ 185 void swapWith(ScopedPointer<ObjectType>& other) noexcept 186 { 187 // Two ScopedPointers should never be able to refer to the same object - if 188 // this happens, you must have done something dodgy! 189 DISTRHO_SAFE_ASSERT_RETURN(object != other.object || this == other.getAddress() || object == nullptr,); 190 191 std::swap(object, other.object); 192 } 193 194 private: 195 //============================================================================== 196 ObjectType* object; 197 198 // (Required as an alternative to the overloaded & operator). 199 const ScopedPointer* getAddress() const noexcept { return this; } 200 201 #ifndef _MSC_VER // (MSVC can't deal with multiple copy constructors) 202 /* The copy constructors are private to stop people accidentally copying a const ScopedPointer 203 (the compiler would let you do so by implicitly casting the source to its raw object pointer). 204 205 A side effect of this is that in a compiler that doesn't support C++11, you may hit an 206 error when you write something like this: 207 208 ScopedPointer<MyClass> m = new MyClass(); // Compile error: copy constructor is private. 209 210 Even though the compiler would normally ignore the assignment here, it can't do so when the 211 copy constructor is private. It's very easy to fix though - just write it like this: 212 213 ScopedPointer<MyClass> m (new MyClass()); // Compiles OK 214 215 It's probably best to use the latter form when writing your object declarations anyway, as 216 this is a better representation of the code that you actually want the compiler to produce. 217 */ 218 # ifdef DISTRHO_PROPER_CPP11_SUPPORT 219 ScopedPointer(const ScopedPointer&) = delete; 220 ScopedPointer& operator=(const ScopedPointer&) = delete; 221 # else 222 ScopedPointer(const ScopedPointer&); 223 ScopedPointer& operator=(const ScopedPointer&); 224 # endif 225 #endif 226 }; 227 228 //============================================================================== 229 /** Compares a ScopedPointer with another pointer. 230 This can be handy for checking whether this is a null pointer. 231 */ 232 template<class ObjectType> 233 bool operator==(const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept 234 { 235 return static_cast<ObjectType*>(pointer1) == pointer2; 236 } 237 238 /** Compares a ScopedPointer with another pointer. 239 This can be handy for checking whether this is a null pointer. 240 */ 241 template<class ObjectType> 242 bool operator!=(const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept 243 { 244 return static_cast<ObjectType*>(pointer1) != pointer2; 245 } 246 247 // ----------------------------------------------------------------------- 248 249 END_NAMESPACE_DISTRHO 250 251 #endif // DISTRHO_SCOPED_POINTER_HPP_INCLUDED