1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
23 * Scott Collins <scc@mozilla.org> (original author)
24 * L. David Baron <dbaron@dbaron.org>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
46 See the User Manual at:
47 http://www.mozilla.org/projects/xpcom/nsCOMPtr.html
51 better than a raw pointer
57 // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design")
60 // for |NS_PRECONDITION|
63 #ifndef nsISupportsUtils_h__
64 #include "nsISupportsUtils.h"
65 // for |nsresult|, |NS_ADDREF|, |NS_GET_TEMPLATE_IID| et al
76 This file defines several macros for internal use only. These macros begin with the
77 prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use
78 only for cross-platform compatibility, and are subject to change without notice.
83 #define NSCAP_FEATURE_INLINE_STARTASSIGNMENT
84 // under VC++, we win by inlining StartAssignment
86 // Also under VC++, at the highest warning level, we are overwhelmed with warnings
87 // about (unused) inline functions being removed. This is to be expected with
88 // templates, so we disable the warning.
89 #pragma warning( disable: 4514 )
92 #define NSCAP_FEATURE_USE_BASE
95 #define NSCAP_FEATURE_TEST_DONTQUERY_CASES
96 #undef NSCAP_FEATURE_USE_BASE
97 //#define NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS
101 |...TEST_DONTQUERY_CASES| and |...DEBUG_PTR_TYPES| introduce some code that is
102 problematic on a select few of our platforms, e.g., QNX. Therefore, I'm providing
103 a mechanism by which these features can be explicitly disabled from the command-line.
106 #ifdef NSCAP_DISABLE_TEST_DONTQUERY_CASES
107 #undef NSCAP_FEATURE_TEST_DONTQUERY_CASES
110 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
111 // Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing
112 // rules. Mark it with the may_alias attribute so that gcc 3.3 and higher
113 // don't reorder instructions based on aliasing assumptions for
114 // this variable. Fortunately, gcc versions < 3.3 do not do any
115 // optimizations that break nsCOMPtr.
117 #define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__))
119 #define NS_MAY_ALIAS_PTR(t) t*
122 #if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES)
123 #define NSCAP_FEATURE_USE_BASE
128 typedef bool NSCAP_BOOL
;
130 typedef PRBool NSCAP_BOOL
;
137 The following three macros (|NSCAP_ADDREF|, |NSCAP_RELEASE|, and |NSCAP_LOG_ASSIGNMENT|)
138 allow external clients the ability to add logging or other interesting debug facilities.
139 In fact, if you want |nsCOMPtr| to participate in the standard logging facility, you
140 provide (e.g., in "nsTraceRefcnt.h") suitable definitions
142 #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr)
143 #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr)
147 #define NSCAP_ADDREF(this, ptr) (ptr)->AddRef()
150 #ifndef NSCAP_RELEASE
151 #define NSCAP_RELEASE(this, ptr) (ptr)->Release()
154 // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging.
155 #ifdef NSCAP_LOG_ASSIGNMENT
156 // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we know
157 // to instantiate |~nsGetterAddRefs| in turn to note the external assignment into
159 #define NSCAP_LOG_EXTERNAL_ASSIGNMENT
161 // ...otherwise, just strip it out of the code
162 #define NSCAP_LOG_ASSIGNMENT(this, ptr)
165 #ifndef NSCAP_LOG_RELEASE
166 #define NSCAP_LOG_RELEASE(this, ptr)
174 VC++4.2 is very picky. To compile under VC++4.2, the classes must be defined
175 in an order that satisfies:
177 nsDerivedSafe < nsCOMPtr
178 already_AddRefed < nsCOMPtr
179 nsCOMPtr < nsGetterAddRefs
181 The other compilers probably won't complain, so please don't reorder these
182 classes, on pain of breaking 4.2 compatibility.
190 nsDerivedSafe
: public T
192 No client should ever see or have to type the name of this class. It is the
193 artifact that makes it a compile-time error to call |AddRef| and |Release|
194 on a |nsCOMPtr|. DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE.
196 See |nsCOMPtr::operator->|, |nsCOMPtr::operator*|, et al.
198 This type should be a nested class inside |nsCOMPtr<T>|.
202 #ifdef HAVE_CPP_ACCESS_CHANGING_USING
206 nsrefcnt
AddRef(void);
207 nsrefcnt
Release(void);
210 #if !defined(AIX) && !defined(IRIX)
211 void operator delete( void*, size_t ); // NOT TO BE IMPLEMENTED
212 // declaring |operator delete| private makes calling delete on an interface pointer a compile error
215 nsDerivedSafe
<T
>& operator=( const T
& ); // NOT TO BE IMPLEMENTED
216 // you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one
219 Compiler warnings and errors: nsDerivedSafe operator=() hides inherited operator=().
220 If you see that, that means somebody checked in a [XP]COM interface class that declares an
221 |operator=()|, and that's _bad_. So bad, in fact, that this declaration exists explicitly
222 to stop people from doing it.
226 nsDerivedSafe(); // NOT TO BE IMPLEMENTED
228 This ctor exists to avoid compile errors and warnings about nsDeriviedSafe using the
229 default ctor but inheriting classes without an empty ctor. See bug 209667.
233 #if !defined(HAVE_CPP_ACCESS_CHANGING_USING) && defined(NEED_CPP_UNUSED_IMPLEMENTATIONS)
236 nsDerivedSafe
<T
>::AddRef()
243 nsDerivedSafe
<T
>::Release()
253 struct already_AddRefed
255 ...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_
256 |AddRef|ing it. You might want to use this as a return type from a function
257 that produces an already |AddRef|ed pointer as a result.
259 See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|.
261 This type should be a nested class inside |nsCOMPtr<T>|.
263 Yes, |already_AddRefed| could have been implemented as an |nsCOMPtr_helper| to
264 avoid adding specialized machinery to |nsCOMPtr| ... but this is the simplest
265 case, and perhaps worth the savings in time and space that its specific
266 implementation affords over the more general solution offered by
270 already_AddRefed( T
* aRawPtr
)
273 // nothing else to do here
276 T
* get() const { return mRawPtr
; }
283 const already_AddRefed
<T
>
284 getter_AddRefs( T
* aRawPtr
)
286 ...makes typing easier, because it deduces the template type, e.g.,
287 you write |dont_AddRef(fooP)| instead of |already_AddRefed<IFoo>(fooP)|.
290 return already_AddRefed
<T
>(aRawPtr
);
295 const already_AddRefed
<T
>
296 getter_AddRefs( const already_AddRefed
<T
> aAlreadyAddRefedPtr
)
298 return aAlreadyAddRefedPtr
;
303 const already_AddRefed
<T
>
304 dont_AddRef( T
* aRawPtr
)
306 return already_AddRefed
<T
>(aRawPtr
);
311 const already_AddRefed
<T
>
312 dont_AddRef( const already_AddRefed
<T
> aAlreadyAddRefedPtr
)
314 return aAlreadyAddRefedPtr
;
319 class nsCOMPtr_helper
321 An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms
322 that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
323 Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
325 Here are the rules for a helper:
326 - it implements |operator()| to produce an interface pointer
327 - (except for its name) |operator()| is a valid [XP]COM `getter'
328 - the interface pointer that it returns is already |AddRef()|ed (as from any good getter)
329 - it matches the type requested with the supplied |nsIID| argument
330 - its constructor provides an optional |nsresult*| that |operator()| can fill
331 in with an error when it is executed
333 See |class nsGetInterface| for an example.
337 virtual nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const = 0;
341 |nsQueryInterface| could have been implemented as an |nsCOMPtr_helper| to
342 avoid adding specialized machinery in |nsCOMPtr|, But |do_QueryInterface|
343 is called often enough that the codesize savings are big enough to
344 warrant the specialcasing.
355 nsQueryInterface( nsISupports
* aRawPtr
)
358 // nothing else to do here
361 nsresult NS_FASTCALL
operator()( const nsIID
& aIID
, void** ) const;
364 nsISupports
* mRawPtr
;
367 class NS_COM_GLUE nsQueryInterfaceWithError
370 nsQueryInterfaceWithError( nsISupports
* aRawPtr
, nsresult
* error
)
374 // nothing else to do here
377 nsresult NS_FASTCALL
operator()( const nsIID
& aIID
, void** ) const;
380 nsISupports
* mRawPtr
;
386 do_QueryInterface( nsISupports
* aRawPtr
)
388 return nsQueryInterface(aRawPtr
);
392 nsQueryInterfaceWithError
393 do_QueryInterface( nsISupports
* aRawPtr
, nsresult
* error
)
395 return nsQueryInterfaceWithError(aRawPtr
, error
);
401 do_QueryInterface( already_AddRefed
<T
>& )
403 // This signature exists solely to _stop_ you from doing the bad thing.
404 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
405 // someone else is an automatic leak. See <http://bugzilla.mozilla.org/show_bug.cgi?id=8221>.
411 do_QueryInterface( already_AddRefed
<T
>&, nsresult
* )
413 // This signature exists solely to _stop_ you from doing the bad thing.
414 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
415 // someone else is an automatic leak. See <http://bugzilla.mozilla.org/show_bug.cgi?id=8221>.
419 ////////////////////////////////////////////////////////////////////////////
420 // Using servicemanager with COMPtrs
421 class NS_COM_GLUE nsGetServiceByCID
424 explicit nsGetServiceByCID(const nsCID
& aCID
)
427 // nothing else to do
430 nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const;
436 class NS_COM_GLUE nsGetServiceByCIDWithError
439 nsGetServiceByCIDWithError( const nsCID
& aCID
, nsresult
* aErrorPtr
)
443 // nothing else to do
446 nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const;
453 class NS_COM_GLUE nsGetServiceByContractID
456 explicit nsGetServiceByContractID(const char* aContractID
)
457 : mContractID(aContractID
)
459 // nothing else to do
462 nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const;
465 const char* mContractID
;
468 class NS_COM_GLUE nsGetServiceByContractIDWithError
471 nsGetServiceByContractIDWithError(const char* aContractID
, nsresult
* aErrorPtr
)
472 : mContractID(aContractID
),
475 // nothing else to do
478 nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const;
481 const char* mContractID
;
488 ...factors implementation for all template versions of |nsCOMPtr|.
490 This should really be an |nsCOMPtr<nsISupports>|, but this wouldn't work
493 Here's the way people normally do things like this
495 template <class T> class Foo { ... };
496 template <> class Foo<void*> { ... };
497 template <class T> class Foo<T*> : private Foo<void*> { ... };
502 nsCOMPtr_base( nsISupports
* rawPtr
= 0 )
505 // nothing else to do here
508 NS_COM_GLUE NS_CONSTRUCTOR_FASTCALL
~nsCOMPtr_base();
510 NS_COM_GLUE
void NS_FASTCALL
assign_with_AddRef( nsISupports
* );
511 NS_COM_GLUE
void NS_FASTCALL
assign_from_qi( const nsQueryInterface
, const nsIID
& );
512 NS_COM_GLUE
void NS_FASTCALL
assign_from_qi_with_error( const nsQueryInterfaceWithError
&, const nsIID
& );
513 NS_COM_GLUE
void NS_FASTCALL
assign_from_gs_cid( const nsGetServiceByCID
, const nsIID
& );
514 NS_COM_GLUE
void NS_FASTCALL
assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError
&, const nsIID
& );
515 NS_COM_GLUE
void NS_FASTCALL
assign_from_gs_contractid( const nsGetServiceByContractID
, const nsIID
& );
516 NS_COM_GLUE
void NS_FASTCALL
assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError
&, const nsIID
& );
517 NS_COM_GLUE
void NS_FASTCALL
assign_from_helper( const nsCOMPtr_helper
&, const nsIID
& );
518 NS_COM_GLUE
void** NS_FASTCALL
begin_assignment();
521 NS_MAY_ALIAS_PTR(nsISupports
) mRawPtr
;
524 assign_assuming_AddRef( nsISupports
* newPtr
)
527 |AddRef()|ing the new value (before entering this function) before
528 |Release()|ing the old lets us safely ignore the self-assignment case.
529 We must, however, be careful only to |Release()| _after_ doing the
530 assignment, in case the |Release()| leads to our _own_ destruction,
531 which would, in turn, cause an incorrect second |Release()| of our old
532 pointer. Thank <waterson@netscape.com> for discovering this.
534 nsISupports
* oldPtr
= mRawPtr
;
536 NSCAP_LOG_ASSIGNMENT(this, newPtr
);
537 NSCAP_LOG_RELEASE(this, oldPtr
);
539 NSCAP_RELEASE(this, oldPtr
);
543 // template <class T> class nsGetterAddRefs;
549 #ifdef NSCAP_FEATURE_USE_BASE
550 : private nsCOMPtr_base
554 #ifdef NSCAP_FEATURE_USE_BASE
555 #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x)
557 #define NSCAP_CTOR_BASE(x) mRawPtr(x)
560 void assign_with_AddRef( nsISupports
* );
561 void assign_from_qi( const nsQueryInterface
, const nsIID
& );
562 void assign_from_qi_with_error( const nsQueryInterfaceWithError
&, const nsIID
& );
563 void assign_from_gs_cid( const nsGetServiceByCID
, const nsIID
& );
564 void assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError
&, const nsIID
& );
565 void assign_from_gs_contractid( const nsGetServiceByContractID
, const nsIID
& );
566 void assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError
&, const nsIID
& );
567 void assign_from_helper( const nsCOMPtr_helper
&, const nsIID
& );
568 void** begin_assignment();
571 assign_assuming_AddRef( T
* newPtr
)
575 NSCAP_LOG_ASSIGNMENT(this, newPtr
);
576 NSCAP_LOG_RELEASE(this, oldPtr
);
578 NSCAP_RELEASE(this, oldPtr
);
586 typedef T element_type
;
588 #ifndef NSCAP_FEATURE_USE_BASE
591 NSCAP_LOG_RELEASE(this, mRawPtr
);
593 NSCAP_RELEASE(this, mRawPtr
);
597 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
599 Assert_NoQueryNeeded()
603 nsCOMPtr
<T
> query_result( do_QueryInterface(mRawPtr
) );
604 NS_ASSERTION(query_result
.get() == mRawPtr
, "QueryInterface needed");
608 #define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
610 #define NSCAP_ASSERT_NO_QUERY_NEEDED()
618 // default constructor
620 NSCAP_LOG_ASSIGNMENT(this, 0);
623 nsCOMPtr( const nsCOMPtr
<T
>& aSmartPtr
)
624 : NSCAP_CTOR_BASE(aSmartPtr
.mRawPtr
)
628 NSCAP_ADDREF(this, mRawPtr
);
629 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
632 nsCOMPtr( T
* aRawPtr
)
633 : NSCAP_CTOR_BASE(aRawPtr
)
634 // construct from a raw pointer (of the right type)
637 NSCAP_ADDREF(this, mRawPtr
);
638 NSCAP_LOG_ASSIGNMENT(this, aRawPtr
);
639 NSCAP_ASSERT_NO_QUERY_NEEDED();
642 nsCOMPtr( const already_AddRefed
<T
>& aSmartPtr
)
643 : NSCAP_CTOR_BASE(aSmartPtr
.mRawPtr
)
644 // construct from |dont_AddRef(expr)|
646 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
647 NSCAP_ASSERT_NO_QUERY_NEEDED();
650 nsCOMPtr( const nsQueryInterface qi
)
652 // construct from |do_QueryInterface(expr)|
654 NSCAP_LOG_ASSIGNMENT(this, 0);
655 assign_from_qi(qi
, NS_GET_TEMPLATE_IID(T
));
658 nsCOMPtr( const nsQueryInterfaceWithError
& qi
)
660 // construct from |do_QueryInterface(expr, &rv)|
662 NSCAP_LOG_ASSIGNMENT(this, 0);
663 assign_from_qi_with_error(qi
, NS_GET_TEMPLATE_IID(T
));
666 nsCOMPtr( const nsGetServiceByCID gs
)
668 // construct from |do_GetService(cid_expr)|
670 NSCAP_LOG_ASSIGNMENT(this, 0);
671 assign_from_gs_cid(gs
, NS_GET_TEMPLATE_IID(T
));
674 nsCOMPtr( const nsGetServiceByCIDWithError
& gs
)
676 // construct from |do_GetService(cid_expr, &rv)|
678 NSCAP_LOG_ASSIGNMENT(this, 0);
679 assign_from_gs_cid_with_error(gs
, NS_GET_TEMPLATE_IID(T
));
682 nsCOMPtr( const nsGetServiceByContractID gs
)
684 // construct from |do_GetService(contractid_expr)|
686 NSCAP_LOG_ASSIGNMENT(this, 0);
687 assign_from_gs_contractid(gs
, NS_GET_TEMPLATE_IID(T
));
690 nsCOMPtr( const nsGetServiceByContractIDWithError
& gs
)
692 // construct from |do_GetService(contractid_expr, &rv)|
694 NSCAP_LOG_ASSIGNMENT(this, 0);
695 assign_from_gs_contractid_with_error(gs
, NS_GET_TEMPLATE_IID(T
));
698 nsCOMPtr( const nsCOMPtr_helper
& helper
)
700 // ...and finally, anything else we might need to construct from
701 // can exploit the |nsCOMPtr_helper| facility
703 NSCAP_LOG_ASSIGNMENT(this, 0);
704 assign_from_helper(helper
, NS_GET_TEMPLATE_IID(T
));
705 NSCAP_ASSERT_NO_QUERY_NEEDED();
709 // Assignment operators
712 operator=( const nsCOMPtr
<T
>& rhs
)
713 // copy assignment operator
715 assign_with_AddRef(rhs
.mRawPtr
);
721 // assign from a raw pointer (of the right type)
723 assign_with_AddRef(rhs
);
724 NSCAP_ASSERT_NO_QUERY_NEEDED();
729 operator=( const already_AddRefed
<T
>& rhs
)
730 // assign from |dont_AddRef(expr)|
732 assign_assuming_AddRef(rhs
.mRawPtr
);
733 NSCAP_ASSERT_NO_QUERY_NEEDED();
738 operator=( const nsQueryInterface rhs
)
739 // assign from |do_QueryInterface(expr)|
741 assign_from_qi(rhs
, NS_GET_TEMPLATE_IID(T
));
746 operator=( const nsQueryInterfaceWithError
& rhs
)
747 // assign from |do_QueryInterface(expr, &rv)|
749 assign_from_qi_with_error(rhs
, NS_GET_TEMPLATE_IID(T
));
754 operator=( const nsGetServiceByCID rhs
)
755 // assign from |do_GetService(cid_expr)|
757 assign_from_gs_cid(rhs
, NS_GET_TEMPLATE_IID(T
));
762 operator=( const nsGetServiceByCIDWithError
& rhs
)
763 // assign from |do_GetService(cid_expr, &rv)|
765 assign_from_gs_cid_with_error(rhs
, NS_GET_TEMPLATE_IID(T
));
770 operator=( const nsGetServiceByContractID rhs
)
771 // assign from |do_GetService(contractid_expr)|
773 assign_from_gs_contractid(rhs
, NS_GET_TEMPLATE_IID(T
));
778 operator=( const nsGetServiceByContractIDWithError
& rhs
)
779 // assign from |do_GetService(contractid_expr, &rv)|
781 assign_from_gs_contractid_with_error(rhs
, NS_GET_TEMPLATE_IID(T
));
786 operator=( const nsCOMPtr_helper
& rhs
)
787 // ...and finally, anything else we might need to assign from
788 // can exploit the |nsCOMPtr_helper| facility.
790 assign_from_helper(rhs
, NS_GET_TEMPLATE_IID(T
));
791 NSCAP_ASSERT_NO_QUERY_NEEDED();
796 swap( nsCOMPtr
<T
>& rhs
)
797 // ...exchange ownership with |rhs|; can save a pair of refcount operations
799 #ifdef NSCAP_FEATURE_USE_BASE
800 nsISupports
* temp
= rhs
.mRawPtr
;
802 T
* temp
= rhs
.mRawPtr
;
804 NSCAP_LOG_ASSIGNMENT(&rhs
, mRawPtr
);
805 NSCAP_LOG_ASSIGNMENT(this, temp
);
806 NSCAP_LOG_RELEASE(this, mRawPtr
);
807 NSCAP_LOG_RELEASE(&rhs
, temp
);
808 rhs
.mRawPtr
= mRawPtr
;
810 // |rhs| maintains the same invariants, so we don't need to |NSCAP_ASSERT_NO_QUERY_NEEDED|
815 // ...exchange ownership with |rhs|; can save a pair of refcount operations
817 #ifdef NSCAP_FEATURE_USE_BASE
818 nsISupports
* temp
= rhs
;
822 NSCAP_LOG_ASSIGNMENT(this, temp
);
823 NSCAP_LOG_RELEASE(this, mRawPtr
);
824 rhs
= reinterpret_cast<T
*>(mRawPtr
);
826 NSCAP_ASSERT_NO_QUERY_NEEDED();
830 // Other pointer operators
834 // return the value of mRawPtr and null out mRawPtr. Useful for
835 // already_AddRefed return values.
844 // Set the target of rhs to the value of mRawPtr and null out mRawPtr.
845 // Useful to avoid unnecessary AddRef/Release pairs with "out"
848 NS_ASSERTION(rhs
, "Null pointer passed to forget!");
856 Prefer the implicit conversion provided automatically by |operator nsDerivedSafe<T>*() const|.
857 Use |get()| to resolve ambiguity or to get a castable pointer.
860 return reinterpret_cast<T
*>(mRawPtr
);
863 operator nsDerivedSafe
<T
>*() const
865 ...makes an |nsCOMPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|,
866 and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator
867 that makes an |nsCOMPtr| substitutable for a raw pointer.
869 Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity.
872 return get_DerivedSafe();
878 NS_PRECONDITION(mRawPtr
!= 0, "You can't dereference a NULL nsCOMPtr with operator->().");
879 return get_DerivedSafe();
882 #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY
883 // broken version for IRIX
887 // This is not intended to be used by clients. See |address_of|
890 return const_cast<nsCOMPtr
<T
>*>(this);
893 #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY
897 // This is not intended to be used by clients. See |address_of|
905 // This is not intended to be used by clients. See |address_of|
911 #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY
917 NS_PRECONDITION(mRawPtr
!= 0, "You can't dereference a NULL nsCOMPtr with operator*().");
918 return *get_DerivedSafe();
923 friend class nsGetterAddRefs
<T
>;
929 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
930 return reinterpret_cast<T
**>(begin_assignment());
932 assign_assuming_AddRef(0);
933 return reinterpret_cast<T
**>(&mRawPtr
);
939 get_DerivedSafe() const
941 return reinterpret_cast<nsDerivedSafe
<T
>*>(mRawPtr
);
949 Specializing |nsCOMPtr| for |nsISupports| allows us to use |nsCOMPtr<nsISupports>| the
950 same way people use |nsISupports*| and |void*|, i.e., as a `catch-all' pointer pointing
951 to any valid [XP]COM interface. Otherwise, an |nsCOMPtr<nsISupports>| would only be able
952 to point to the single [XP]COM-correct |nsISupports| instance within an object; extra
953 querying ensues. Clients need to be able to pass around arbitrary interface pointers,
954 without hassles, through intermediary code that doesn't know the exact type.
957 NS_SPECIALIZE_TEMPLATE
958 class nsCOMPtr
<nsISupports
>
959 : private nsCOMPtr_base
962 typedef nsISupports element_type
;
968 // default constructor
970 NSCAP_LOG_ASSIGNMENT(this, 0);
973 nsCOMPtr( const nsCOMPtr
<nsISupports
>& aSmartPtr
)
974 : nsCOMPtr_base(aSmartPtr
.mRawPtr
)
978 NSCAP_ADDREF(this, mRawPtr
);
979 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
982 nsCOMPtr( nsISupports
* aRawPtr
)
983 : nsCOMPtr_base(aRawPtr
)
984 // construct from a raw pointer (of the right type)
987 NSCAP_ADDREF(this, mRawPtr
);
988 NSCAP_LOG_ASSIGNMENT(this, aRawPtr
);
991 nsCOMPtr( const already_AddRefed
<nsISupports
>& aSmartPtr
)
992 : nsCOMPtr_base(aSmartPtr
.mRawPtr
)
993 // construct from |dont_AddRef(expr)|
995 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
998 nsCOMPtr( const nsQueryInterface qi
)
1000 // assign from |do_QueryInterface(expr)|
1002 NSCAP_LOG_ASSIGNMENT(this, 0);
1003 assign_from_qi(qi
, NS_GET_IID(nsISupports
));
1006 nsCOMPtr( const nsQueryInterfaceWithError
& qi
)
1008 // assign from |do_QueryInterface(expr, &rv)|
1010 NSCAP_LOG_ASSIGNMENT(this, 0);
1011 assign_from_qi_with_error(qi
, NS_GET_IID(nsISupports
));
1014 nsCOMPtr( const nsGetServiceByCID gs
)
1016 // assign from |do_GetService(cid_expr)|
1018 NSCAP_LOG_ASSIGNMENT(this, 0);
1019 assign_from_gs_cid(gs
, NS_GET_IID(nsISupports
));
1022 nsCOMPtr( const nsGetServiceByCIDWithError
& gs
)
1024 // assign from |do_GetService(cid_expr, &rv)|
1026 NSCAP_LOG_ASSIGNMENT(this, 0);
1027 assign_from_gs_cid_with_error(gs
, NS_GET_IID(nsISupports
));
1030 nsCOMPtr( const nsGetServiceByContractID gs
)
1032 // assign from |do_GetService(contractid_expr)|
1034 NSCAP_LOG_ASSIGNMENT(this, 0);
1035 assign_from_gs_contractid(gs
, NS_GET_IID(nsISupports
));
1038 nsCOMPtr( const nsGetServiceByContractIDWithError
& gs
)
1040 // assign from |do_GetService(contractid_expr, &rv)|
1042 NSCAP_LOG_ASSIGNMENT(this, 0);
1043 assign_from_gs_contractid_with_error(gs
, NS_GET_IID(nsISupports
));
1046 nsCOMPtr( const nsCOMPtr_helper
& helper
)
1048 // ...and finally, anything else we might need to construct from
1049 // can exploit the |nsCOMPtr_helper| facility
1051 NSCAP_LOG_ASSIGNMENT(this, 0);
1052 assign_from_helper(helper
, NS_GET_IID(nsISupports
));
1056 // Assignment operators
1058 nsCOMPtr
<nsISupports
>&
1059 operator=( const nsCOMPtr
<nsISupports
>& rhs
)
1060 // copy assignment operator
1062 assign_with_AddRef(rhs
.mRawPtr
);
1066 nsCOMPtr
<nsISupports
>&
1067 operator=( nsISupports
* rhs
)
1068 // assign from a raw pointer (of the right type)
1070 assign_with_AddRef(rhs
);
1074 nsCOMPtr
<nsISupports
>&
1075 operator=( const already_AddRefed
<nsISupports
>& rhs
)
1076 // assign from |dont_AddRef(expr)|
1078 assign_assuming_AddRef(rhs
.mRawPtr
);
1082 nsCOMPtr
<nsISupports
>&
1083 operator=( const nsQueryInterface rhs
)
1084 // assign from |do_QueryInterface(expr)|
1086 assign_from_qi(rhs
, NS_GET_IID(nsISupports
));
1090 nsCOMPtr
<nsISupports
>&
1091 operator=( const nsQueryInterfaceWithError
& rhs
)
1092 // assign from |do_QueryInterface(expr, &rv)|
1094 assign_from_qi_with_error(rhs
, NS_GET_IID(nsISupports
));
1098 nsCOMPtr
<nsISupports
>&
1099 operator=( const nsGetServiceByCID rhs
)
1100 // assign from |do_GetService(cid_expr)|
1102 assign_from_gs_cid(rhs
, NS_GET_IID(nsISupports
));
1106 nsCOMPtr
<nsISupports
>&
1107 operator=( const nsGetServiceByCIDWithError
& rhs
)
1108 // assign from |do_GetService(cid_expr, &rv)|
1110 assign_from_gs_cid_with_error(rhs
, NS_GET_IID(nsISupports
));
1114 nsCOMPtr
<nsISupports
>&
1115 operator=( const nsGetServiceByContractID rhs
)
1116 // assign from |do_GetService(contractid_expr)|
1118 assign_from_gs_contractid(rhs
, NS_GET_IID(nsISupports
));
1122 nsCOMPtr
<nsISupports
>&
1123 operator=( const nsGetServiceByContractIDWithError
& rhs
)
1124 // assign from |do_GetService(contractid_expr, &rv)|
1126 assign_from_gs_contractid_with_error(rhs
, NS_GET_IID(nsISupports
));
1130 nsCOMPtr
<nsISupports
>&
1131 operator=( const nsCOMPtr_helper
& rhs
)
1132 // ...and finally, anything else we might need to assign from
1133 // can exploit the |nsCOMPtr_helper| facility.
1135 assign_from_helper(rhs
, NS_GET_IID(nsISupports
));
1140 swap( nsCOMPtr
<nsISupports
>& rhs
)
1141 // ...exchange ownership with |rhs|; can save a pair of refcount operations
1143 nsISupports
* temp
= rhs
.mRawPtr
;
1144 NSCAP_LOG_ASSIGNMENT(&rhs
, mRawPtr
);
1145 NSCAP_LOG_ASSIGNMENT(this, temp
);
1146 NSCAP_LOG_RELEASE(this, mRawPtr
);
1147 NSCAP_LOG_RELEASE(&rhs
, temp
);
1148 rhs
.mRawPtr
= mRawPtr
;
1153 swap( nsISupports
*& rhs
)
1154 // ...exchange ownership with |rhs|; can save a pair of refcount operations
1156 nsISupports
* temp
= rhs
;
1157 NSCAP_LOG_ASSIGNMENT(this, temp
);
1158 NSCAP_LOG_RELEASE(this, mRawPtr
);
1164 forget( nsISupports
** rhs
)
1165 // Set the target of rhs to the value of mRawPtr and null out mRawPtr.
1166 // Useful to avoid unnecessary AddRef/Release pairs with "out"
1169 NS_ASSERTION(rhs
, "Null pointer passed to forget!");
1174 // Other pointer operators
1179 Prefer the implicit conversion provided automatically by |operator nsDerivedSafe<nsISupports>*() const|.
1180 Use |get()| to resolve ambiguity or to get a castable pointer.
1183 return reinterpret_cast<nsISupports
*>(mRawPtr
);
1186 operator nsDerivedSafe
<nsISupports
>*() const
1188 ...makes an |nsCOMPtr| act like its underlying raw pointer type (except against |AddRef()|, |Release()|,
1189 and |delete|) whenever it is used in a context where a raw pointer is expected. It is this operator
1190 that makes an |nsCOMPtr| substitutable for a raw pointer.
1192 Prefer the implicit use of this operator to calling |get()|, except where necessary to resolve ambiguity.
1195 return get_DerivedSafe();
1198 nsDerivedSafe
<nsISupports
>*
1201 NS_PRECONDITION(mRawPtr
!= 0, "You can't dereference a NULL nsCOMPtr with operator->().");
1202 return get_DerivedSafe();
1205 #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY
1206 // broken version for IRIX
1208 nsCOMPtr
<nsISupports
>*
1210 // This is not intended to be used by clients. See |address_of|
1213 return const_cast<nsCOMPtr
<nsISupports
>*>(this);
1216 #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY
1218 nsCOMPtr
<nsISupports
>*
1220 // This is not intended to be used by clients. See |address_of|
1226 const nsCOMPtr
<nsISupports
>*
1228 // This is not intended to be used by clients. See |address_of|
1234 #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY
1238 nsDerivedSafe
<nsISupports
>&
1241 NS_PRECONDITION(mRawPtr
!= 0, "You can't dereference a NULL nsCOMPtr with operator*().");
1242 return *get_DerivedSafe();
1247 friend class nsGetterAddRefs
<nsISupports
>;
1253 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
1254 return reinterpret_cast<nsISupports
**>(begin_assignment());
1256 assign_assuming_AddRef(0);
1257 return reinterpret_cast<nsISupports
**>(&mRawPtr
);
1262 nsDerivedSafe
<nsISupports
>*
1263 get_DerivedSafe() const
1265 return reinterpret_cast<nsDerivedSafe
<nsISupports
>*>(mRawPtr
);
1270 #ifndef NSCAP_FEATURE_USE_BASE
1273 nsCOMPtr
<T
>::assign_with_AddRef( nsISupports
* rawPtr
)
1276 NSCAP_ADDREF(this, rawPtr
);
1277 assign_assuming_AddRef(reinterpret_cast<T
*>(rawPtr
));
1282 nsCOMPtr
<T
>::assign_from_qi( const nsQueryInterface qi
, const nsIID
& aIID
)
1285 if ( NS_FAILED( qi(aIID
, &newRawPtr
) ) )
1287 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1292 nsCOMPtr
<T
>::assign_from_qi_with_error( const nsQueryInterfaceWithError
& qi
, const nsIID
& aIID
)
1295 if ( NS_FAILED( qi(aIID
, &newRawPtr
) ) )
1297 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1302 nsCOMPtr
<T
>::assign_from_gs_cid( const nsGetServiceByCID gs
, const nsIID
& aIID
)
1305 if ( NS_FAILED( gs(aIID
, &newRawPtr
) ) )
1307 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1312 nsCOMPtr
<T
>::assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError
& gs
, const nsIID
& aIID
)
1315 if ( NS_FAILED( gs(aIID
, &newRawPtr
) ) )
1317 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1322 nsCOMPtr
<T
>::assign_from_gs_contractid( const nsGetServiceByContractID gs
, const nsIID
& aIID
)
1325 if ( NS_FAILED( gs(aIID
, &newRawPtr
) ) )
1327 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1332 nsCOMPtr
<T
>::assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError
& gs
, const nsIID
& aIID
)
1335 if ( NS_FAILED( gs(aIID
, &newRawPtr
) ) )
1337 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1342 nsCOMPtr
<T
>::assign_from_helper( const nsCOMPtr_helper
& helper
, const nsIID
& aIID
)
1345 if ( NS_FAILED( helper(aIID
, &newRawPtr
) ) )
1347 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1352 nsCOMPtr
<T
>::begin_assignment()
1354 assign_assuming_AddRef(0);
1355 union { T
** mT
; void** mVoid
; } result
;
1356 result
.mT
= &mRawPtr
;
1357 return result
.mVoid
;
1361 #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY
1363 // This is the broken version for IRIX, which can't handle the version below.
1368 address_of( const nsCOMPtr
<T
>& aPtr
)
1370 return aPtr
.get_address();
1373 #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY
1378 address_of( nsCOMPtr
<T
>& aPtr
)
1380 return aPtr
.get_address();
1386 address_of( const nsCOMPtr
<T
>& aPtr
)
1388 return aPtr
.get_address();
1391 #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY
1394 class nsGetterAddRefs
1398 This class is designed to be used for anonymous temporary objects in the
1399 argument list of calls that return COM interface pointers, e.g.,
1401 nsCOMPtr<IFoo> fooP;
1402 ...->QueryInterface(iid, getter_AddRefs(fooP))
1404 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
1406 When initialized with a |nsCOMPtr|, as in the example above, it returns
1407 a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|QueryInterface| in this
1410 This type should be a nested class inside |nsCOMPtr<T>|.
1415 nsGetterAddRefs( nsCOMPtr
<T
>& aSmartPtr
)
1416 : mTargetSmartPtr(aSmartPtr
)
1418 // nothing else to do
1421 #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
1424 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1425 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void *>(address_of(mTargetSmartPtr
)), mTargetSmartPtr
.get());
1428 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
1429 mTargetSmartPtr
.Assert_NoQueryNeeded();
1436 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
1439 operator nsISupports
**()
1441 return reinterpret_cast<nsISupports
**>(mTargetSmartPtr
.StartAssignment());
1446 return mTargetSmartPtr
.StartAssignment();
1452 return *(mTargetSmartPtr
.StartAssignment());
1456 nsCOMPtr
<T
>& mTargetSmartPtr
;
1460 NS_SPECIALIZE_TEMPLATE
1461 class nsGetterAddRefs
<nsISupports
>
1465 nsGetterAddRefs( nsCOMPtr
<nsISupports
>& aSmartPtr
)
1466 : mTargetSmartPtr(aSmartPtr
)
1468 // nothing else to do
1471 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1474 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void *>(address_of(mTargetSmartPtr
)), mTargetSmartPtr
.get());
1480 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
1483 operator nsISupports
**()
1485 return mTargetSmartPtr
.StartAssignment();
1491 return *(mTargetSmartPtr
.StartAssignment());
1495 nsCOMPtr
<nsISupports
>& mTargetSmartPtr
;
1502 getter_AddRefs( nsCOMPtr
<T
>& aSmartPtr
)
1504 Used around a |nsCOMPtr| when
1505 ...makes the class |nsGetterAddRefs<T>| invisible.
1508 return nsGetterAddRefs
<T
>(aSmartPtr
);
1513 // Comparing two |nsCOMPtr|s
1515 template <class T
, class U
>
1518 operator==( const nsCOMPtr
<T
>& lhs
, const nsCOMPtr
<U
>& rhs
)
1520 return static_cast<const T
*>(lhs
.get()) == static_cast<const U
*>(rhs
.get());
1524 template <class T
, class U
>
1527 operator!=( const nsCOMPtr
<T
>& lhs
, const nsCOMPtr
<U
>& rhs
)
1529 return static_cast<const T
*>(lhs
.get()) != static_cast<const U
*>(rhs
.get());
1533 // Comparing an |nsCOMPtr| to a raw pointer
1535 template <class T
, class U
>
1538 operator==( const nsCOMPtr
<T
>& lhs
, const U
* rhs
)
1540 return static_cast<const T
*>(lhs
.get()) == rhs
;
1543 template <class T
, class U
>
1546 operator==( const U
* lhs
, const nsCOMPtr
<T
>& rhs
)
1548 return lhs
== static_cast<const T
*>(rhs
.get());
1551 template <class T
, class U
>
1554 operator!=( const nsCOMPtr
<T
>& lhs
, const U
* rhs
)
1556 return static_cast<const T
*>(lhs
.get()) != rhs
;
1559 template <class T
, class U
>
1562 operator!=( const U
* lhs
, const nsCOMPtr
<T
>& rhs
)
1564 return lhs
!= static_cast<const T
*>(rhs
.get());
1567 // To avoid ambiguities caused by the presence of builtin |operator==|s
1568 // creating a situation where one of the |operator==| defined above
1569 // has a better conversion for one argument and the builtin has a
1570 // better conversion for the other argument, define additional
1571 // |operator==| without the |const| on the raw pointer.
1572 // See bug 65664 for details.
1574 // This is defined by an autoconf test, but VC++ also has a bug that
1575 // prevents us from using these. (It also, fortunately, has the bug
1576 // that we don't need them either.)
1577 #if defined(_MSC_VER) && (_MSC_VER < 1310)
1578 #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ
1579 #define NSCAP_DONT_PROVIDE_NONCONST_OPEQ
1583 #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ
1584 template <class T
, class U
>
1587 operator==( const nsCOMPtr
<T
>& lhs
, U
* rhs
)
1589 return static_cast<const T
*>(lhs
.get()) == const_cast<const U
*>(rhs
);
1592 template <class T
, class U
>
1595 operator==( U
* lhs
, const nsCOMPtr
<T
>& rhs
)
1597 return const_cast<const U
*>(lhs
) == static_cast<const T
*>(rhs
.get());
1600 template <class T
, class U
>
1603 operator!=( const nsCOMPtr
<T
>& lhs
, U
* rhs
)
1605 return static_cast<const T
*>(lhs
.get()) != const_cast<const U
*>(rhs
);
1608 template <class T
, class U
>
1611 operator!=( U
* lhs
, const nsCOMPtr
<T
>& rhs
)
1613 return const_cast<const U
*>(lhs
) != static_cast<const T
*>(rhs
.get());
1619 // Comparing an |nsCOMPtr| to |0|
1626 operator==( const nsCOMPtr
<T
>& lhs
, NSCAP_Zero
* rhs
)
1627 // specifically to allow |smartPtr == 0|
1629 return static_cast<const void*>(lhs
.get()) == reinterpret_cast<const void*>(rhs
);
1635 operator==( NSCAP_Zero
* lhs
, const nsCOMPtr
<T
>& rhs
)
1636 // specifically to allow |0 == smartPtr|
1638 return reinterpret_cast<const void*>(lhs
) == static_cast<const void*>(rhs
.get());
1644 operator!=( const nsCOMPtr
<T
>& lhs
, NSCAP_Zero
* rhs
)
1645 // specifically to allow |smartPtr != 0|
1647 return static_cast<const void*>(lhs
.get()) != reinterpret_cast<const void*>(rhs
);
1653 operator!=( NSCAP_Zero
* lhs
, const nsCOMPtr
<T
>& rhs
)
1654 // specifically to allow |0 != smartPtr|
1656 return reinterpret_cast<const void*>(lhs
) != static_cast<const void*>(rhs
.get());
1660 #ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO
1662 // We need to explicitly define comparison operators for `int'
1663 // because the compiler is lame.
1668 operator==( const nsCOMPtr
<T
>& lhs
, int rhs
)
1669 // specifically to allow |smartPtr == 0|
1671 return static_cast<const void*>(lhs
.get()) == reinterpret_cast<const void*>(rhs
);
1677 operator==( int lhs
, const nsCOMPtr
<T
>& rhs
)
1678 // specifically to allow |0 == smartPtr|
1680 return reinterpret_cast<const void*>(lhs
) == static_cast<const void*>(rhs
.get());
1683 #endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
1685 // Comparing any two [XP]COM objects for identity
1689 SameCOMIdentity( nsISupports
* lhs
, nsISupports
* rhs
)
1691 return nsCOMPtr
<nsISupports
>( do_QueryInterface(lhs
) ) == nsCOMPtr
<nsISupports
>( do_QueryInterface(rhs
) );
1696 template <class SourceType
, class DestinationType
>
1699 CallQueryInterface( nsCOMPtr
<SourceType
>& aSourcePtr
, DestinationType
** aDestPtr
)
1701 return CallQueryInterface(aSourcePtr
.get(), aDestPtr
);
1704 #endif // !defined(nsCOMPtr_h___)