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/. */
7 #ifndef mozilla_RefPtr_h
8 #define mozilla_RefPtr_h
10 #include "mozilla/AlreadyAddRefed.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/DbgMacro.h"
15 #include <type_traits>
17 /*****************************************************************************/
19 // template <class T> class RefPtrGetterAddRefs;
21 class nsQueryReferent
;
22 class nsCOMPtr_helper
;
29 class StaticLocalRefPtr
;
36 #endif // defined(XP_WIN)
38 // Traditionally, RefPtr supports automatic refcounting of any pointer type
39 // with AddRef() and Release() methods that follow the traditional semantics.
41 // This traits class can be specialized to operate on other pointer types. For
42 // example, we specialize this trait for opaque FFI types that represent
43 // refcounted objects in Rust.
45 // Given the use of ConstRemovingRefPtrTraits below, U should not be a const-
49 static void AddRef(U
* aPtr
) { aPtr
->AddRef(); }
50 static void Release(U
* aPtr
) { aPtr
->Release(); }
53 } // namespace mozilla
56 class MOZ_IS_REFPTR RefPtr
{
58 void assign_with_AddRef(T
* aRawPtr
) {
60 ConstRemovingRefPtrTraits
<T
>::AddRef(aRawPtr
);
62 assign_assuming_AddRef(aRawPtr
);
65 void assign_assuming_AddRef(T
* aNewPtr
) {
69 ConstRemovingRefPtrTraits
<T
>::Release(oldPtr
);
74 T
* MOZ_OWNING_REF mRawPtr
;
77 typedef T element_type
;
81 ConstRemovingRefPtrTraits
<T
>::Release(mRawPtr
);
89 // default constructor
92 RefPtr(const RefPtr
<T
>& aSmartPtr
)
93 : mRawPtr(aSmartPtr
.mRawPtr
)
97 ConstRemovingRefPtrTraits
<T
>::AddRef(mRawPtr
);
101 RefPtr(RefPtr
<T
>&& aRefPtr
) : mRawPtr(aRefPtr
.mRawPtr
) {
102 aRefPtr
.mRawPtr
= nullptr;
105 // construct from a raw pointer (of the right type)
107 MOZ_IMPLICIT
RefPtr(T
* aRawPtr
) : mRawPtr(aRawPtr
) {
109 ConstRemovingRefPtrTraits
<T
>::AddRef(mRawPtr
);
113 MOZ_IMPLICIT
RefPtr(decltype(nullptr)) : mRawPtr(nullptr) {}
115 template <typename I
,
116 typename
= std::enable_if_t
<std::is_convertible_v
<I
*, T
*>>>
117 MOZ_IMPLICIT
RefPtr(already_AddRefed
<I
>& aSmartPtr
)
118 : mRawPtr(aSmartPtr
.take())
119 // construct from |already_AddRefed|
122 template <typename I
,
123 typename
= std::enable_if_t
<std::is_convertible_v
<I
*, T
*>>>
124 MOZ_IMPLICIT
RefPtr(already_AddRefed
<I
>&& aSmartPtr
)
125 : mRawPtr(aSmartPtr
.take())
126 // construct from |otherRefPtr.forget()|
129 template <typename I
,
130 typename
= std::enable_if_t
<std::is_convertible_v
<I
*, T
*>>>
131 MOZ_IMPLICIT
RefPtr(const RefPtr
<I
>& aSmartPtr
)
132 : mRawPtr(aSmartPtr
.get())
133 // copy-construct from a smart pointer with a related pointer type
136 ConstRemovingRefPtrTraits
<T
>::AddRef(mRawPtr
);
140 template <typename I
,
141 typename
= std::enable_if_t
<std::is_convertible_v
<I
*, T
*>>>
142 MOZ_IMPLICIT
RefPtr(RefPtr
<I
>&& aSmartPtr
)
143 : mRawPtr(aSmartPtr
.forget().take())
144 // construct from |Move(RefPtr<SomeSubclassOfT>)|.
147 MOZ_IMPLICIT
RefPtr(const nsQueryReferent
& aHelper
);
148 MOZ_IMPLICIT
RefPtr(const nsCOMPtr_helper
& aHelper
);
150 MOZ_IMPLICIT
RefPtr(const mozilla::mscom::AgileReference
& aAgileRef
);
151 #endif // defined(XP_WIN)
153 // Defined in OwningNonNull.h
155 MOZ_IMPLICIT
RefPtr(const mozilla::OwningNonNull
<U
>& aOther
);
157 // Defined in StaticLocalPtr.h
159 MOZ_IMPLICIT
RefPtr(const mozilla::StaticLocalRefPtr
<U
>& aOther
);
161 // Defined in StaticPtr.h
163 MOZ_IMPLICIT
RefPtr(const mozilla::StaticRefPtr
<U
>& aOther
);
165 // Assignment operators
167 RefPtr
<T
>& operator=(decltype(nullptr)) {
168 assign_assuming_AddRef(nullptr);
172 RefPtr
<T
>& operator=(const RefPtr
<T
>& aRhs
)
173 // copy assignment operator
175 assign_with_AddRef(aRhs
.mRawPtr
);
179 template <typename I
>
180 RefPtr
<T
>& operator=(const RefPtr
<I
>& aRhs
)
181 // assign from an RefPtr of a related pointer type
183 assign_with_AddRef(aRhs
.get());
187 RefPtr
<T
>& operator=(T
* aRhs
)
188 // assign from a raw pointer (of the right type)
190 assign_with_AddRef(aRhs
);
194 template <typename I
>
195 RefPtr
<T
>& operator=(already_AddRefed
<I
>& aRhs
)
196 // assign from |already_AddRefed|
198 assign_assuming_AddRef(aRhs
.take());
202 template <typename I
>
203 RefPtr
<T
>& operator=(already_AddRefed
<I
>&& aRhs
)
204 // assign from |otherRefPtr.forget()|
206 assign_assuming_AddRef(aRhs
.take());
210 RefPtr
<T
>& operator=(const nsQueryReferent
& aQueryReferent
);
211 RefPtr
<T
>& operator=(const nsCOMPtr_helper
& aHelper
);
213 RefPtr
<T
>& operator=(const mozilla::mscom::AgileReference
& aAgileRef
);
214 #endif // defined(XP_WIN)
216 template <typename I
,
217 typename
= std::enable_if_t
<std::is_convertible_v
<I
*, T
*>>>
218 RefPtr
<T
>& operator=(RefPtr
<I
>&& aRefPtr
) {
219 assign_assuming_AddRef(aRefPtr
.forget().take());
223 // Defined in OwningNonNull.h
225 RefPtr
<T
>& operator=(const mozilla::OwningNonNull
<U
>& aOther
);
227 // Defined in StaticLocalPtr.h
229 RefPtr
<T
>& operator=(const mozilla::StaticLocalRefPtr
<U
>& aOther
);
231 // Defined in StaticPtr.h
233 RefPtr
<T
>& operator=(const mozilla::StaticRefPtr
<U
>& aOther
);
235 // Other pointer operators
237 void swap(RefPtr
<T
>& aRhs
)
238 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
240 T
* temp
= aRhs
.mRawPtr
;
241 aRhs
.mRawPtr
= mRawPtr
;
246 // ...exchange ownership with |aRhs|; can save a pair of refcount operations
253 already_AddRefed
<T
> MOZ_MAY_CALL_AFTER_MUST_RETURN
forget()
254 // return the value of mRawPtr and null out mRawPtr. Useful for
255 // already_AddRefed return values.
259 return already_AddRefed
<T
>(temp
);
262 template <typename I
>
263 void forget(I
** aRhs
)
264 // Set the target of aRhs to the value of mRawPtr and null out mRawPtr.
265 // Useful to avoid unnecessary AddRef/Release pairs with "out"
266 // parameters where aRhs bay be a T** or an I** where I is a base class
269 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
274 void forget(nsISupports
** aRhs
) {
275 MOZ_ASSERT(aRhs
, "Null pointer passed to forget!");
276 *aRhs
= ToSupports(mRawPtr
);
282 Prefer the implicit conversion provided automatically by |operator T*()
283 const|. Use |get()| to resolve ambiguity or to get a castable pointer.
286 return const_cast<T
*>(mRawPtr
);
291 ...makes an |RefPtr| act like its underlying raw pointer type whenever it
292 is used in a context where a raw pointer is expected. It is this operator
293 that makes an |RefPtr| substitutable for a raw pointer.
295 Prefer the implicit use of this operator to calling |get()|, except where
296 necessary to resolve ambiguity.
302 // Don't allow implicit conversion of temporary RefPtr to raw pointer,
303 // because the refcount might be one and the pointer will immediately become
305 operator T
*() const&& = delete;
307 // These are needed to avoid the deleted operator above. XXX Why is operator!
308 // needed separately? Shouldn't the compiler prefer using the non-deleted
309 // operator bool instead of the deleted operator T*?
310 explicit operator bool() const { return !!mRawPtr
; }
311 bool operator!() const { return !mRawPtr
; }
313 T
* operator->() const MOZ_NO_ADDREF_RELEASE_ON_RETURN
{
314 MOZ_ASSERT(mRawPtr
!= nullptr,
315 "You can't dereference a NULL RefPtr with operator->().");
319 template <typename R
, typename
... Args
>
321 typedef R (T::*member_function
)(Args
...);
323 member_function mFunction
;
326 Proxy(T
* aRawPtr
, member_function aFunction
)
327 : mRawPtr(aRawPtr
), mFunction(aFunction
) {}
328 template <typename
... ActualArgs
>
329 R
operator()(ActualArgs
&&... aArgs
) {
330 return ((*mRawPtr
).*mFunction
)(std::forward
<ActualArgs
>(aArgs
)...);
334 template <typename R
, typename
... Args
>
335 Proxy
<R
, Args
...> operator->*(R (T::*aFptr
)(Args
...)) const {
336 MOZ_ASSERT(mRawPtr
!= nullptr,
337 "You can't dereference a NULL RefPtr with operator->*().");
338 return Proxy
<R
, Args
...>(get(), aFptr
);
341 RefPtr
<T
>* get_address()
342 // This is not intended to be used by clients. See |address_of|
348 const RefPtr
<T
>* get_address() const
349 // This is not intended to be used by clients. See |address_of|
356 T
& operator*() const {
357 MOZ_ASSERT(mRawPtr
!= nullptr,
358 "You can't dereference a NULL RefPtr with operator*().");
362 T
** StartAssignment() {
363 assign_assuming_AddRef(nullptr);
364 return reinterpret_cast<T
**>(&mRawPtr
);
368 // This helper class makes |RefPtr<const T>| possible by casting away
369 // the constness from the pointer when calling AddRef() and Release().
371 // This is necessary because AddRef() and Release() implementations can't
372 // generally expected to be const themselves (without heavy use of |mutable|
373 // and |const_cast| in their own implementations).
375 // This should be sound because while |RefPtr<const T>| provides a
376 // const view of an object, the object itself should not be const (it
377 // would have to be allocated as |new const T| or similar to be const).
379 struct ConstRemovingRefPtrTraits
{
380 static void AddRef(U
* aPtr
) { mozilla::RefPtrTraits
<U
>::AddRef(aPtr
); }
381 static void Release(U
* aPtr
) { mozilla::RefPtrTraits
<U
>::Release(aPtr
); }
384 struct ConstRemovingRefPtrTraits
<const U
> {
385 static void AddRef(const U
* aPtr
) {
386 mozilla::RefPtrTraits
<U
>::AddRef(const_cast<U
*>(aPtr
));
388 static void Release(const U
* aPtr
) {
389 mozilla::RefPtrTraits
<U
>::Release(const_cast<U
*>(aPtr
));
394 class nsCycleCollectionTraversalCallback
;
395 template <typename T
>
396 void CycleCollectionNoteChild(nsCycleCollectionTraversalCallback
& aCallback
,
397 T
* aChild
, const char* aName
, uint32_t aFlags
);
399 template <typename T
>
400 inline void ImplCycleCollectionUnlink(RefPtr
<T
>& aField
) {
404 template <typename T
>
405 inline void ImplCycleCollectionTraverse(
406 nsCycleCollectionTraversalCallback
& aCallback
, RefPtr
<T
>& aField
,
407 const char* aName
, uint32_t aFlags
= 0) {
408 CycleCollectionNoteChild(aCallback
, aField
.get(), aName
, aFlags
);
412 inline RefPtr
<T
>* address_of(RefPtr
<T
>& aPtr
) {
413 return aPtr
.get_address();
417 inline const RefPtr
<T
>* address_of(const RefPtr
<T
>& aPtr
) {
418 return aPtr
.get_address();
422 class RefPtrGetterAddRefs
426 This class is designed to be used for anonymous temporary objects in the
427 argument list of calls that return COM interface pointers, e.g.,
430 ...->GetAddRefedPointer(getter_AddRefs(fooP))
432 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
434 When initialized with a |RefPtr|, as in the example above, it returns
435 a |void**|, a |T**|, or an |nsISupports**| as needed, that the
436 outer call (|GetAddRefedPointer| in this case) can fill in.
438 This type should be a nested class inside |RefPtr<T>|.
442 explicit RefPtrGetterAddRefs(RefPtr
<T
>& aSmartPtr
)
443 : mTargetSmartPtr(aSmartPtr
) {
444 // nothing else to do
448 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
451 operator T
**() { return mTargetSmartPtr
.StartAssignment(); }
453 T
*& operator*() { return *(mTargetSmartPtr
.StartAssignment()); }
456 RefPtr
<T
>& mTargetSmartPtr
;
460 inline RefPtrGetterAddRefs
<T
> getter_AddRefs(RefPtr
<T
>& aSmartPtr
)
462 Used around a |RefPtr| when
463 ...makes the class |RefPtrGetterAddRefs<T>| invisible.
466 return RefPtrGetterAddRefs
<T
>(aSmartPtr
);
469 // Comparing two |RefPtr|s
471 template <class T
, class U
>
472 inline bool operator==(const RefPtr
<T
>& aLhs
, const RefPtr
<U
>& aRhs
) {
473 return static_cast<const T
*>(aLhs
.get()) == static_cast<const U
*>(aRhs
.get());
476 template <class T
, class U
>
477 inline bool operator!=(const RefPtr
<T
>& aLhs
, const RefPtr
<U
>& aRhs
) {
478 return static_cast<const T
*>(aLhs
.get()) != static_cast<const U
*>(aRhs
.get());
481 // Comparing an |RefPtr| to a raw pointer
483 template <class T
, class U
>
484 inline bool operator==(const RefPtr
<T
>& aLhs
, const U
* aRhs
) {
485 return static_cast<const T
*>(aLhs
.get()) == static_cast<const U
*>(aRhs
);
488 template <class T
, class U
>
489 inline bool operator==(const U
* aLhs
, const RefPtr
<T
>& aRhs
) {
490 return static_cast<const U
*>(aLhs
) == static_cast<const T
*>(aRhs
.get());
493 template <class T
, class U
>
494 inline bool operator!=(const RefPtr
<T
>& aLhs
, const U
* aRhs
) {
495 return static_cast<const T
*>(aLhs
.get()) != static_cast<const U
*>(aRhs
);
498 template <class T
, class U
>
499 inline bool operator!=(const U
* aLhs
, const RefPtr
<T
>& aRhs
) {
500 return static_cast<const U
*>(aLhs
) != static_cast<const T
*>(aRhs
.get());
503 template <class T
, class U
>
504 inline bool operator==(const RefPtr
<T
>& aLhs
, U
* aRhs
) {
505 return static_cast<const T
*>(aLhs
.get()) == const_cast<const U
*>(aRhs
);
508 template <class T
, class U
>
509 inline bool operator==(U
* aLhs
, const RefPtr
<T
>& aRhs
) {
510 return const_cast<const U
*>(aLhs
) == static_cast<const T
*>(aRhs
.get());
513 template <class T
, class U
>
514 inline bool operator!=(const RefPtr
<T
>& aLhs
, U
* aRhs
) {
515 return static_cast<const T
*>(aLhs
.get()) != const_cast<const U
*>(aRhs
);
518 template <class T
, class U
>
519 inline bool operator!=(U
* aLhs
, const RefPtr
<T
>& aRhs
) {
520 return const_cast<const U
*>(aLhs
) != static_cast<const T
*>(aRhs
.get());
523 // Comparing an |RefPtr| to |nullptr|
526 inline bool operator==(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
527 return aLhs
.get() == nullptr;
531 inline bool operator==(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
532 return nullptr == aRhs
.get();
536 inline bool operator!=(const RefPtr
<T
>& aLhs
, decltype(nullptr)) {
537 return aLhs
.get() != nullptr;
541 inline bool operator!=(decltype(nullptr), const RefPtr
<T
>& aRhs
) {
542 return nullptr != aRhs
.get();
548 std::ostream
& operator<<(std::ostream
& aOut
, const RefPtr
<T
>& aObj
) {
549 return mozilla::DebugValue(aOut
, aObj
.get());
552 /*****************************************************************************/
555 inline already_AddRefed
<T
> do_AddRef(T
* aObj
) {
561 inline already_AddRefed
<T
> do_AddRef(const RefPtr
<T
>& aObj
) {
568 template <typename T
>
569 class AlignmentFinder
;
571 // Provide a specialization of AlignmentFinder to allow MOZ_ALIGNOF(RefPtr<T>)
572 // with an incomplete T.
573 template <typename T
>
574 class AlignmentFinder
<RefPtr
<T
>> {
576 static const size_t alignment
= alignof(T
*);
580 * Helper function to be able to conveniently write things like:
582 * already_AddRefed<T>
585 * return MakeAndAddRef<T>(...);
588 template <typename T
, typename
... Args
>
589 already_AddRefed
<T
> MakeAndAddRef(Args
&&... aArgs
) {
590 RefPtr
<T
> p(new T(std::forward
<Args
>(aArgs
)...));
595 * Helper function to be able to conveniently write things like:
598 * MakeRefPtr<ErrorCallbackRunnable<nsIDOMGetUserMediaSuccessCallback>>(
599 * mOnSuccess, mOnFailure, *error, mWindowID);
601 template <typename T
, typename
... Args
>
602 RefPtr
<T
> MakeRefPtr(Args
&&... aArgs
) {
603 RefPtr
<T
> p(new T(std::forward
<Args
>(aArgs
)...));
607 } // namespace mozilla
610 * Deduction guide to allow simple `RefPtr` definitions from an
611 * already_AddRefed<T> without repeating the type, e.g.:
613 * RefPtr ptr = MakeAndAddRef<SomeType>(...);
615 template <typename T
>
616 RefPtr(already_AddRefed
<T
>) -> RefPtr
<T
>;
618 #endif /* mozilla_RefPtr_h */