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 /* Typed temporary pointers for reference-counted smart pointers. */ 8 9 #ifndef AlreadyAddRefed_h 10 #define AlreadyAddRefed_h 11 12 #include "mozilla/Assertions.h" 13 #include "mozilla/Attributes.h" 14 #include "mozilla/Move.h" 15 16 namespace mozilla { 17 18 struct unused_t; 19 20 } // namespace mozilla 21 22 /** 23 * already_AddRefed cooperates with reference counting smart pointers to enable 24 * you to assign in a pointer _without_ |AddRef|ing it. You might want to use 25 * this as a return type from a function that returns an already |AddRef|ed 26 * pointer. 27 * 28 * TODO Move already_AddRefed to namespace mozilla. This has not yet been done 29 * because of the sheer number of usages of already_AddRefed. 30 */ 31 template<class T> 32 struct MOZ_MUST_USE MOZ_NON_AUTOABLE already_AddRefed 33 { 34 /* 35 * We want to allow returning nullptr from functions returning 36 * already_AddRefed<T>, for simplicity. But we also don't want to allow 37 * returning raw T*, instead preferring creation of already_AddRefed<T> from 38 * a reference counting smart pointer. 39 * 40 * We address the latter requirement by making the (T*) constructor explicit. 41 * But |return nullptr| won't consider an explicit constructor, so we need 42 * another constructor to handle it. Plain old (decltype(nullptr)) doesn't 43 * cut it, because if nullptr is emulated as __null (with type int or long), 44 * passing nullptr to an int/long parameter triggers compiler warnings. We 45 * need a type that no one can pass accidentally; a pointer-to-member-function 46 * (where no such function exists) does the trick nicely. 47 * 48 * That handles the return-value case. What about for locals, argument types, 49 * and so on? |already_AddRefed<T>(nullptr)| considers both overloads (and 50 * the (already_AddRefed<T>&&) overload as well!), so there's an ambiguity. 51 * We can target true nullptr using decltype(nullptr), but we can't target 52 * emulated nullptr the same way, because passing __null to an int/long 53 * parameter triggers compiler warnings. So just give up on this, and provide 54 * this behavior through the default constructor. 55 * 56 * We can revert to simply explicit (T*) and implicit (decltype(nullptr)) when 57 * nullptr no longer needs to be emulated to support the ancient b2g compiler. 58 * (The () overload could also be removed, if desired, if we changed callers.) 59 */ already_AddRefedalready_AddRefed60 already_AddRefed() : mRawPtr(nullptr) {} 61 62 // The return and argument types here are arbitrarily selected so no 63 // corresponding member function exists. 64 typedef void (already_AddRefed::* MatchNullptr)(double, float); already_AddRefedalready_AddRefed65 MOZ_IMPLICIT already_AddRefed(MatchNullptr aRawPtr) : mRawPtr(nullptr) {} 66 already_AddRefedalready_AddRefed67 explicit already_AddRefed(T* aRawPtr) : mRawPtr(aRawPtr) {} 68 69 // Disallow copy constructor and copy assignment operator: move semantics used instead. 70 already_AddRefed(const already_AddRefed<T>& aOther) = delete; 71 already_AddRefed<T>& operator=(const already_AddRefed<T>& aOther) = delete; 72 already_AddRefedalready_AddRefed73 already_AddRefed(already_AddRefed<T>&& aOther) : mRawPtr(aOther.take()) {} 74 75 already_AddRefed<T>& operator=(already_AddRefed<T>&& aOther) 76 { 77 mRawPtr = aOther.take(); 78 return *this; 79 } 80 81 /** 82 * This helper is useful in cases like 83 * 84 * already_AddRefed<BaseClass> 85 * Foo() 86 * { 87 * RefPtr<SubClass> x = ...; 88 * return x.forget(); 89 * } 90 * 91 * The autoconversion allows one to omit the idiom 92 * 93 * RefPtr<BaseClass> y = x.forget(); 94 * return y.forget(); 95 * 96 * Note that nsRefPtr is the XPCOM reference counting smart pointer class. 97 */ 98 template <typename U> already_AddRefedalready_AddRefed99 MOZ_IMPLICIT already_AddRefed(already_AddRefed<U>&& aOther) : mRawPtr(aOther.take()) {} 100 ~already_AddRefedalready_AddRefed101 ~already_AddRefed() { MOZ_ASSERT(!mRawPtr); } 102 103 // Specialize the unused operator<< for already_AddRefed, to allow 104 // nsCOMPtr<nsIFoo> foo; 105 // Unused << foo.forget(); 106 // Note that nsCOMPtr is the XPCOM reference counting smart pointer class. 107 friend void operator<<(const mozilla::unused_t& aUnused, 108 const already_AddRefed<T>& aRhs) 109 { 110 auto mutableAlreadyAddRefed = const_cast<already_AddRefed<T>*>(&aRhs); 111 aUnused << mutableAlreadyAddRefed->take(); 112 } 113 takealready_AddRefed114 MOZ_WARN_UNUSED_RESULT T* take() 115 { 116 T* rawPtr = mRawPtr; 117 mRawPtr = nullptr; 118 return rawPtr; 119 } 120 121 /** 122 * This helper provides a static_cast replacement for already_AddRefed, so 123 * if you have 124 * 125 * already_AddRefed<Parent> F(); 126 * 127 * you can write 128 * 129 * already_AddRefed<Child> 130 * G() 131 * { 132 * return F().downcast<Child>(); 133 * } 134 */ 135 template<class U> downcastalready_AddRefed136 already_AddRefed<U> downcast() 137 { 138 U* tmp = static_cast<U*>(mRawPtr); 139 mRawPtr = nullptr; 140 return already_AddRefed<U>(tmp); 141 } 142 143 private: 144 T* MOZ_OWNING_REF mRawPtr; 145 }; 146 147 #endif // AlreadyAddRefed_h 148