1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* DEPRECATED: Use UniquePtr.h instead. */ 8 9 #ifndef mozilla_Scoped_h 10 #define mozilla_Scoped_h 11 12 /* 13 * DEPRECATED: Use UniquePtr.h instead. 14 * 15 * Resource Acquisition Is Initialization is a programming idiom used 16 * to write robust code that is able to deallocate resources properly, 17 * even in presence of execution errors or exceptions that need to be 18 * propagated. The Scoped* classes defined in this header perform the 19 * deallocation of the resource they hold once program execution 20 * reaches the end of the scope for which they have been defined. 21 * 22 * This header provides the following RAII classes: 23 * 24 * - |ScopedFreePtr| - a container for a pointer, that automatically calls 25 * |free()| at the end of the scope; 26 * - |ScopedDeletePtr| - a container for a pointer, that automatically calls 27 * |delete| at the end of the scope; 28 * 29 * |ScopedDeleteArray| is removed in favor of |UniquePtr<T[]>|. 30 * 31 * The general scenario for each of the RAII classes is the following: 32 * 33 * ScopedClass foo(create_value()); 34 * // ... In this scope, |foo| is defined. Use |foo.get()| or |foo.rwget()| 35 * to access the value. 36 * // ... In case of |return| or |throw|, |foo| is deallocated automatically. 37 * // ... If |foo| needs to be returned or stored, use |foo.forget()| 38 * 39 * Note that the RAII classes defined in this header do _not_ perform any form 40 * of reference-counting or garbage-collection. These classes have exactly two 41 * behaviors: 42 * 43 * - if |forget()| has not been called, the resource is always deallocated at 44 * the end of the scope; 45 * - if |forget()| has been called, any control on the resource is unbound 46 * and the resource is not deallocated by the class. 47 * 48 * Extension: 49 * 50 * In addition, this header provides class |Scoped| and macros |SCOPED_TEMPLATE| 51 * and |MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE| to simplify the definition 52 * of RAII classes for other scenarios. These macros have been used to 53 * automatically close file descriptors/file handles when reaching the end of 54 * the scope, graphics contexts, etc. 55 */ 56 57 #include "mozilla/Assertions.h" 58 #include "mozilla/Attributes.h" 59 #include "mozilla/GuardObjects.h" 60 #include "mozilla/Move.h" 61 62 namespace mozilla { 63 64 /* 65 * Scoped is a helper to create RAII wrappers 66 * Type argument |Traits| is expected to have the following structure: 67 * 68 * struct Traits 69 * { 70 * // Define the type of the value stored in the wrapper 71 * typedef value_type type; 72 * // Returns the value corresponding to the uninitialized or freed state 73 * const static type empty(); 74 * // Release resources corresponding to the wrapped value 75 * // This function is responsible for not releasing an |empty| value 76 * const static void release(type); 77 * } 78 */ 79 template<typename Traits> 80 class MOZ_NON_TEMPORARY_CLASS Scoped 81 { 82 public: 83 typedef typename Traits::type Resource; 84 Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)85 explicit Scoped(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) 86 : mValue(Traits::empty()) 87 { 88 MOZ_GUARD_OBJECT_NOTIFIER_INIT; 89 } 90 Scoped(const Resource & aValue MOZ_GUARD_OBJECT_NOTIFIER_PARAM)91 explicit Scoped(const Resource& aValue 92 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 93 : mValue(aValue) 94 { 95 MOZ_GUARD_OBJECT_NOTIFIER_INIT; 96 } 97 98 /* Move constructor. */ Scoped(Scoped && aOther MOZ_GUARD_OBJECT_NOTIFIER_PARAM)99 Scoped(Scoped&& aOther 100 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 101 : mValue(Move(aOther.mValue)) 102 { 103 MOZ_GUARD_OBJECT_NOTIFIER_INIT; 104 aOther.mValue = Traits::empty(); 105 } 106 ~Scoped()107 ~Scoped() { Traits::release(mValue); } 108 109 // Constant getter 110 operator const Resource&() const { return mValue; } 111 const Resource& operator->() const { return mValue; } get()112 const Resource& get() const { return mValue; } 113 // Non-constant getter. rwget()114 Resource& rwget() { return mValue; } 115 116 /* 117 * Forget the resource. 118 * 119 * Once |forget| has been called, the |Scoped| is neutralized, i.e. it will 120 * have no effect at destruction (unless it is reset to another resource by 121 * |operator=|). 122 * 123 * @return The original resource. 124 */ forget()125 Resource forget() 126 { 127 Resource tmp = mValue; 128 mValue = Traits::empty(); 129 return tmp; 130 } 131 132 /* 133 * Perform immediate clean-up of this |Scoped|. 134 * 135 * If this |Scoped| is currently empty, this method has no effect. 136 */ dispose()137 void dispose() 138 { 139 Traits::release(mValue); 140 mValue = Traits::empty(); 141 } 142 143 bool operator==(const Resource& aOther) const { return mValue == aOther; } 144 145 /* 146 * Replace the resource with another resource. 147 * 148 * Calling |operator=| has the side-effect of triggering clean-up. If you do 149 * not want to trigger clean-up, you should first invoke |forget|. 150 * 151 * @return this 152 */ 153 Scoped& operator=(const Resource& aOther) { return reset(aOther); } 154 reset(const Resource & aOther)155 Scoped& reset(const Resource& aOther) 156 { 157 Traits::release(mValue); 158 mValue = aOther; 159 return *this; 160 } 161 162 /* Move assignment operator. */ 163 Scoped& operator=(Scoped&& aRhs) 164 { 165 MOZ_ASSERT(&aRhs != this, "self-move-assignment not allowed"); 166 this->~Scoped(); 167 new(this) Scoped(Move(aRhs)); 168 return *this; 169 } 170 171 private: 172 explicit Scoped(const Scoped& aValue) = delete; 173 Scoped& operator=(const Scoped& aValue) = delete; 174 175 private: 176 Resource mValue; 177 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 178 }; 179 180 /* 181 * SCOPED_TEMPLATE defines a templated class derived from Scoped 182 * This allows to implement templates such as ScopedFreePtr. 183 * 184 * @param name The name of the class to define. 185 * @param Traits A struct implementing clean-up. See the implementations 186 * for more details. 187 */ 188 #define SCOPED_TEMPLATE(name, Traits) \ 189 template<typename Type> \ 190 struct MOZ_NON_TEMPORARY_CLASS name : public mozilla::Scoped<Traits<Type> > \ 191 { \ 192 typedef mozilla::Scoped<Traits<Type> > Super; \ 193 typedef typename Super::Resource Resource; \ 194 name& operator=(Resource aRhs) \ 195 { \ 196 Super::operator=(aRhs); \ 197 return *this; \ 198 } \ 199 name& operator=(name&& aRhs) \ 200 { \ 201 Super::operator=(Move(aRhs)); \ 202 return *this; \ 203 } \ 204 explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM) \ 205 : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) \ 206 {} \ 207 explicit name(Resource aRhs \ 208 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ 209 : Super(aRhs \ 210 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ 211 {} \ 212 name(name&& aRhs \ 213 MOZ_GUARD_OBJECT_NOTIFIER_PARAM) \ 214 : Super(Move(aRhs) \ 215 MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) \ 216 {} \ 217 private: \ 218 explicit name(name&) = delete; \ 219 name& operator=(name&) = delete; \ 220 }; 221 222 /* 223 * ScopedFreePtr is a RAII wrapper for pointers that need to be free()d. 224 * 225 * struct S { ... }; 226 * ScopedFreePtr<S> foo = malloc(sizeof(S)); 227 * ScopedFreePtr<char> bar = strdup(str); 228 */ 229 template<typename T> 230 struct ScopedFreePtrTraits 231 { 232 typedef T* type; emptyScopedFreePtrTraits233 static T* empty() { return nullptr; } releaseScopedFreePtrTraits234 static void release(T* aPtr) { free(aPtr); } 235 }; 236 SCOPED_TEMPLATE(ScopedFreePtr, ScopedFreePtrTraits) 237 238 /* 239 * ScopedDeletePtr is a RAII wrapper for pointers that need to be deleted. 240 * 241 * struct S { ... }; 242 * ScopedDeletePtr<S> foo = new S(); 243 */ 244 template<typename T> 245 struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T> 246 { releaseScopedDeletePtrTraits247 static void release(T* aPtr) { delete aPtr; } 248 }; 249 SCOPED_TEMPLATE(ScopedDeletePtr, ScopedDeletePtrTraits) 250 251 /* 252 * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped 253 * pointers for types with custom deleters; just overload 254 * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for 255 * type T. 256 * 257 * @param name The name of the class to define. 258 * @param Type A struct implementing clean-up. See the implementations 259 * for more details. 260 * *param Deleter The function that is used to delete/destroy/free a 261 * non-null value of Type*. 262 * 263 * Example: 264 * 265 * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedPRFileDesc, PRFileDesc, \ 266 * PR_Close) 267 * ... 268 * { 269 * ScopedPRFileDesc file(PR_OpenFile(...)); 270 * ... 271 * } // file is closed with PR_Close here 272 */ 273 #define MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(name, Type, Deleter) \ 274 template <> inline void TypeSpecificDelete(Type* aValue) { Deleter(aValue); } \ 275 typedef ::mozilla::TypeSpecificScopedPointer<Type> name; 276 277 template <typename T> void TypeSpecificDelete(T* aValue); 278 279 template <typename T> 280 struct TypeSpecificScopedPointerTraits 281 { 282 typedef T* type; emptyTypeSpecificScopedPointerTraits283 static type empty() { return nullptr; } releaseTypeSpecificScopedPointerTraits284 static void release(type aValue) 285 { 286 if (aValue) { 287 TypeSpecificDelete(aValue); 288 } 289 } 290 }; 291 292 SCOPED_TEMPLATE(TypeSpecificScopedPointer, TypeSpecificScopedPointerTraits) 293 294 } /* namespace mozilla */ 295 296 #endif /* mozilla_Scoped_h */ 297