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)
170 struct already_AddRefed
172 ...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_
173 |AddRef|ing it. You might want to use this as a return type from a function
174 that produces an already |AddRef|ed pointer as a result.
176 See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|.
178 This type should be a nested class inside |nsCOMPtr<T>|.
180 Yes, |already_AddRefed| could have been implemented as an |nsCOMPtr_helper| to
181 avoid adding specialized machinery to |nsCOMPtr| ... but this is the simplest
182 case, and perhaps worth the savings in time and space that its specific
183 implementation affords over the more general solution offered by
187 already_AddRefed( T
* aRawPtr
)
190 // nothing else to do here
193 T
* get() const { return mRawPtr
; }
200 const already_AddRefed
<T
>
201 getter_AddRefs( T
* aRawPtr
)
203 ...makes typing easier, because it deduces the template type, e.g.,
204 you write |dont_AddRef(fooP)| instead of |already_AddRefed<IFoo>(fooP)|.
207 return already_AddRefed
<T
>(aRawPtr
);
212 const already_AddRefed
<T
>
213 getter_AddRefs( const already_AddRefed
<T
> aAlreadyAddRefedPtr
)
215 return aAlreadyAddRefedPtr
;
220 const already_AddRefed
<T
>
221 dont_AddRef( T
* aRawPtr
)
223 return already_AddRefed
<T
>(aRawPtr
);
228 const already_AddRefed
<T
>
229 dont_AddRef( const already_AddRefed
<T
> aAlreadyAddRefedPtr
)
231 return aAlreadyAddRefedPtr
;
236 class nsCOMPtr_helper
238 An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms
239 that are more convenient to call, and more efficient to use with |nsCOMPtr|s.
240 Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc.
242 Here are the rules for a helper:
243 - it implements |operator()| to produce an interface pointer
244 - (except for its name) |operator()| is a valid [XP]COM `getter'
245 - the interface pointer that it returns is already |AddRef()|ed (as from any good getter)
246 - it matches the type requested with the supplied |nsIID| argument
247 - its constructor provides an optional |nsresult*| that |operator()| can fill
248 in with an error when it is executed
250 See |class nsGetInterface| for an example.
254 virtual nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const = 0;
258 |nsQueryInterface| could have been implemented as an |nsCOMPtr_helper| to
259 avoid adding specialized machinery in |nsCOMPtr|, But |do_QueryInterface|
260 is called often enough that the codesize savings are big enough to
261 warrant the specialcasing.
272 nsQueryInterface( nsISupports
* aRawPtr
)
275 // nothing else to do here
278 nsresult NS_FASTCALL
operator()( const nsIID
& aIID
, void** ) const;
281 nsISupports
* mRawPtr
;
284 class NS_COM_GLUE nsQueryInterfaceWithError
287 nsQueryInterfaceWithError( nsISupports
* aRawPtr
, nsresult
* error
)
291 // nothing else to do here
294 nsresult NS_FASTCALL
operator()( const nsIID
& aIID
, void** ) const;
297 nsISupports
* mRawPtr
;
303 do_QueryInterface( nsISupports
* aRawPtr
)
305 return nsQueryInterface(aRawPtr
);
309 nsQueryInterfaceWithError
310 do_QueryInterface( nsISupports
* aRawPtr
, nsresult
* error
)
312 return nsQueryInterfaceWithError(aRawPtr
, error
);
318 do_QueryInterface( already_AddRefed
<T
>& )
320 // This signature exists solely to _stop_ you from doing the bad thing.
321 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
322 // someone else is an automatic leak. See <http://bugzilla.mozilla.org/show_bug.cgi?id=8221>.
328 do_QueryInterface( already_AddRefed
<T
>&, nsresult
* )
330 // This signature exists solely to _stop_ you from doing the bad thing.
331 // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by
332 // someone else is an automatic leak. See <http://bugzilla.mozilla.org/show_bug.cgi?id=8221>.
336 ////////////////////////////////////////////////////////////////////////////
337 // Using servicemanager with COMPtrs
338 class NS_COM_GLUE nsGetServiceByCID
341 explicit nsGetServiceByCID(const nsCID
& aCID
)
344 // nothing else to do
347 nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const;
353 class NS_COM_GLUE nsGetServiceByCIDWithError
356 nsGetServiceByCIDWithError( const nsCID
& aCID
, nsresult
* aErrorPtr
)
360 // nothing else to do
363 nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const;
370 class NS_COM_GLUE nsGetServiceByContractID
373 explicit nsGetServiceByContractID(const char* aContractID
)
374 : mContractID(aContractID
)
376 // nothing else to do
379 nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const;
382 const char* mContractID
;
385 class NS_COM_GLUE nsGetServiceByContractIDWithError
388 nsGetServiceByContractIDWithError(const char* aContractID
, nsresult
* aErrorPtr
)
389 : mContractID(aContractID
),
392 // nothing else to do
395 nsresult NS_FASTCALL
operator()( const nsIID
&, void** ) const;
398 const char* mContractID
;
405 ...factors implementation for all template versions of |nsCOMPtr|.
407 This should really be an |nsCOMPtr<nsISupports>|, but this wouldn't work
410 Here's the way people normally do things like this
412 template <class T> class Foo { ... };
413 template <> class Foo<void*> { ... };
414 template <class T> class Foo<T*> : private Foo<void*> { ... };
419 nsCOMPtr_base( nsISupports
* rawPtr
= 0 )
422 // nothing else to do here
425 NS_COM_GLUE NS_CONSTRUCTOR_FASTCALL
~nsCOMPtr_base();
427 NS_COM_GLUE
void NS_FASTCALL
assign_with_AddRef( nsISupports
* );
428 NS_COM_GLUE
void NS_FASTCALL
assign_from_qi( const nsQueryInterface
, const nsIID
& );
429 NS_COM_GLUE
void NS_FASTCALL
assign_from_qi_with_error( const nsQueryInterfaceWithError
&, const nsIID
& );
430 NS_COM_GLUE
void NS_FASTCALL
assign_from_gs_cid( const nsGetServiceByCID
, const nsIID
& );
431 NS_COM_GLUE
void NS_FASTCALL
assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError
&, const nsIID
& );
432 NS_COM_GLUE
void NS_FASTCALL
assign_from_gs_contractid( const nsGetServiceByContractID
, const nsIID
& );
433 NS_COM_GLUE
void NS_FASTCALL
assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError
&, const nsIID
& );
434 NS_COM_GLUE
void NS_FASTCALL
assign_from_helper( const nsCOMPtr_helper
&, const nsIID
& );
435 NS_COM_GLUE
void** NS_FASTCALL
begin_assignment();
438 NS_MAY_ALIAS_PTR(nsISupports
) mRawPtr
;
441 assign_assuming_AddRef( nsISupports
* newPtr
)
444 |AddRef()|ing the new value (before entering this function) before
445 |Release()|ing the old lets us safely ignore the self-assignment case.
446 We must, however, be careful only to |Release()| _after_ doing the
447 assignment, in case the |Release()| leads to our _own_ destruction,
448 which would, in turn, cause an incorrect second |Release()| of our old
449 pointer. Thank <waterson@netscape.com> for discovering this.
451 nsISupports
* oldPtr
= mRawPtr
;
453 NSCAP_LOG_ASSIGNMENT(this, newPtr
);
454 NSCAP_LOG_RELEASE(this, oldPtr
);
456 NSCAP_RELEASE(this, oldPtr
);
460 // template <class T> class nsGetterAddRefs;
466 #ifdef NSCAP_FEATURE_USE_BASE
467 : private nsCOMPtr_base
471 #ifdef NSCAP_FEATURE_USE_BASE
472 #define NSCAP_CTOR_BASE(x) nsCOMPtr_base(x)
474 #define NSCAP_CTOR_BASE(x) mRawPtr(x)
477 void assign_with_AddRef( nsISupports
* );
478 void assign_from_qi( const nsQueryInterface
, const nsIID
& );
479 void assign_from_qi_with_error( const nsQueryInterfaceWithError
&, const nsIID
& );
480 void assign_from_gs_cid( const nsGetServiceByCID
, const nsIID
& );
481 void assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError
&, const nsIID
& );
482 void assign_from_gs_contractid( const nsGetServiceByContractID
, const nsIID
& );
483 void assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError
&, const nsIID
& );
484 void assign_from_helper( const nsCOMPtr_helper
&, const nsIID
& );
485 void** begin_assignment();
488 assign_assuming_AddRef( T
* newPtr
)
492 NSCAP_LOG_ASSIGNMENT(this, newPtr
);
493 NSCAP_LOG_RELEASE(this, oldPtr
);
495 NSCAP_RELEASE(this, oldPtr
);
503 typedef T element_type
;
505 #ifndef NSCAP_FEATURE_USE_BASE
508 NSCAP_LOG_RELEASE(this, mRawPtr
);
510 NSCAP_RELEASE(this, mRawPtr
);
514 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
516 Assert_NoQueryNeeded()
520 nsCOMPtr
<T
> query_result( do_QueryInterface(mRawPtr
) );
521 NS_ASSERTION(query_result
.get() == mRawPtr
, "QueryInterface needed");
525 #define NSCAP_ASSERT_NO_QUERY_NEEDED() Assert_NoQueryNeeded();
527 #define NSCAP_ASSERT_NO_QUERY_NEEDED()
535 // default constructor
537 NSCAP_LOG_ASSIGNMENT(this, 0);
540 nsCOMPtr( const nsCOMPtr
<T
>& aSmartPtr
)
541 : NSCAP_CTOR_BASE(aSmartPtr
.mRawPtr
)
545 NSCAP_ADDREF(this, mRawPtr
);
546 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
549 nsCOMPtr( T
* aRawPtr
)
550 : NSCAP_CTOR_BASE(aRawPtr
)
551 // construct from a raw pointer (of the right type)
554 NSCAP_ADDREF(this, mRawPtr
);
555 NSCAP_LOG_ASSIGNMENT(this, aRawPtr
);
556 NSCAP_ASSERT_NO_QUERY_NEEDED();
559 nsCOMPtr( const already_AddRefed
<T
>& aSmartPtr
)
560 : NSCAP_CTOR_BASE(aSmartPtr
.mRawPtr
)
561 // construct from |dont_AddRef(expr)|
563 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
564 NSCAP_ASSERT_NO_QUERY_NEEDED();
567 nsCOMPtr( const nsQueryInterface qi
)
569 // construct from |do_QueryInterface(expr)|
571 NSCAP_LOG_ASSIGNMENT(this, 0);
572 assign_from_qi(qi
, NS_GET_TEMPLATE_IID(T
));
575 nsCOMPtr( const nsQueryInterfaceWithError
& qi
)
577 // construct from |do_QueryInterface(expr, &rv)|
579 NSCAP_LOG_ASSIGNMENT(this, 0);
580 assign_from_qi_with_error(qi
, NS_GET_TEMPLATE_IID(T
));
583 nsCOMPtr( const nsGetServiceByCID gs
)
585 // construct from |do_GetService(cid_expr)|
587 NSCAP_LOG_ASSIGNMENT(this, 0);
588 assign_from_gs_cid(gs
, NS_GET_TEMPLATE_IID(T
));
591 nsCOMPtr( const nsGetServiceByCIDWithError
& gs
)
593 // construct from |do_GetService(cid_expr, &rv)|
595 NSCAP_LOG_ASSIGNMENT(this, 0);
596 assign_from_gs_cid_with_error(gs
, NS_GET_TEMPLATE_IID(T
));
599 nsCOMPtr( const nsGetServiceByContractID gs
)
601 // construct from |do_GetService(contractid_expr)|
603 NSCAP_LOG_ASSIGNMENT(this, 0);
604 assign_from_gs_contractid(gs
, NS_GET_TEMPLATE_IID(T
));
607 nsCOMPtr( const nsGetServiceByContractIDWithError
& gs
)
609 // construct from |do_GetService(contractid_expr, &rv)|
611 NSCAP_LOG_ASSIGNMENT(this, 0);
612 assign_from_gs_contractid_with_error(gs
, NS_GET_TEMPLATE_IID(T
));
615 nsCOMPtr( const nsCOMPtr_helper
& helper
)
617 // ...and finally, anything else we might need to construct from
618 // can exploit the |nsCOMPtr_helper| facility
620 NSCAP_LOG_ASSIGNMENT(this, 0);
621 assign_from_helper(helper
, NS_GET_TEMPLATE_IID(T
));
622 NSCAP_ASSERT_NO_QUERY_NEEDED();
626 // Assignment operators
629 operator=( const nsCOMPtr
<T
>& rhs
)
630 // copy assignment operator
632 assign_with_AddRef(rhs
.mRawPtr
);
638 // assign from a raw pointer (of the right type)
640 assign_with_AddRef(rhs
);
641 NSCAP_ASSERT_NO_QUERY_NEEDED();
646 operator=( const already_AddRefed
<T
>& rhs
)
647 // assign from |dont_AddRef(expr)|
649 assign_assuming_AddRef(rhs
.mRawPtr
);
650 NSCAP_ASSERT_NO_QUERY_NEEDED();
655 operator=( const nsQueryInterface rhs
)
656 // assign from |do_QueryInterface(expr)|
658 assign_from_qi(rhs
, NS_GET_TEMPLATE_IID(T
));
663 operator=( const nsQueryInterfaceWithError
& rhs
)
664 // assign from |do_QueryInterface(expr, &rv)|
666 assign_from_qi_with_error(rhs
, NS_GET_TEMPLATE_IID(T
));
671 operator=( const nsGetServiceByCID rhs
)
672 // assign from |do_GetService(cid_expr)|
674 assign_from_gs_cid(rhs
, NS_GET_TEMPLATE_IID(T
));
679 operator=( const nsGetServiceByCIDWithError
& rhs
)
680 // assign from |do_GetService(cid_expr, &rv)|
682 assign_from_gs_cid_with_error(rhs
, NS_GET_TEMPLATE_IID(T
));
687 operator=( const nsGetServiceByContractID rhs
)
688 // assign from |do_GetService(contractid_expr)|
690 assign_from_gs_contractid(rhs
, NS_GET_TEMPLATE_IID(T
));
695 operator=( const nsGetServiceByContractIDWithError
& rhs
)
696 // assign from |do_GetService(contractid_expr, &rv)|
698 assign_from_gs_contractid_with_error(rhs
, NS_GET_TEMPLATE_IID(T
));
703 operator=( const nsCOMPtr_helper
& rhs
)
704 // ...and finally, anything else we might need to assign from
705 // can exploit the |nsCOMPtr_helper| facility.
707 assign_from_helper(rhs
, NS_GET_TEMPLATE_IID(T
));
708 NSCAP_ASSERT_NO_QUERY_NEEDED();
713 swap( nsCOMPtr
<T
>& rhs
)
714 // ...exchange ownership with |rhs|; can save a pair of refcount operations
716 #ifdef NSCAP_FEATURE_USE_BASE
717 nsISupports
* temp
= rhs
.mRawPtr
;
719 T
* temp
= rhs
.mRawPtr
;
721 NSCAP_LOG_ASSIGNMENT(&rhs
, mRawPtr
);
722 NSCAP_LOG_ASSIGNMENT(this, temp
);
723 NSCAP_LOG_RELEASE(this, mRawPtr
);
724 NSCAP_LOG_RELEASE(&rhs
, temp
);
725 rhs
.mRawPtr
= mRawPtr
;
727 // |rhs| maintains the same invariants, so we don't need to |NSCAP_ASSERT_NO_QUERY_NEEDED|
732 // ...exchange ownership with |rhs|; can save a pair of refcount operations
734 #ifdef NSCAP_FEATURE_USE_BASE
735 nsISupports
* temp
= rhs
;
739 NSCAP_LOG_ASSIGNMENT(this, temp
);
740 NSCAP_LOG_RELEASE(this, mRawPtr
);
741 rhs
= reinterpret_cast<T
*>(mRawPtr
);
743 NSCAP_ASSERT_NO_QUERY_NEEDED();
747 // Other pointer operators
751 // return the value of mRawPtr and null out mRawPtr. Useful for
752 // already_AddRefed return values.
761 // Set the target of rhs to the value of mRawPtr and null out mRawPtr.
762 // Useful to avoid unnecessary AddRef/Release pairs with "out"
765 NS_ASSERTION(rhs
, "Null pointer passed to forget!");
773 Prefer the implicit conversion provided automatically by |operator T*() const|.
774 Use |get()| to resolve ambiguity or to get a castable pointer.
777 return reinterpret_cast<T
*>(mRawPtr
);
782 ...makes an |nsCOMPtr| act like its underlying raw pointer type whenever it
783 is used in a context where a raw pointer is expected. It is this operator
784 that makes an |nsCOMPtr| substitutable for a raw pointer.
786 Prefer the implicit use of this operator to calling |get()|, except where
787 necessary to resolve ambiguity.
796 NS_PRECONDITION(mRawPtr
!= 0, "You can't dereference a NULL nsCOMPtr with operator->().");
800 #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY
801 // broken version for IRIX
805 // This is not intended to be used by clients. See |address_of|
808 return const_cast<nsCOMPtr
<T
>*>(this);
811 #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY
815 // This is not intended to be used by clients. See |address_of|
823 // This is not intended to be used by clients. See |address_of|
829 #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY
835 NS_PRECONDITION(mRawPtr
!= 0, "You can't dereference a NULL nsCOMPtr with operator*().");
842 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
843 return reinterpret_cast<T
**>(begin_assignment());
845 assign_assuming_AddRef(0);
846 return reinterpret_cast<T
**>(&mRawPtr
);
854 Specializing |nsCOMPtr| for |nsISupports| allows us to use |nsCOMPtr<nsISupports>| the
855 same way people use |nsISupports*| and |void*|, i.e., as a `catch-all' pointer pointing
856 to any valid [XP]COM interface. Otherwise, an |nsCOMPtr<nsISupports>| would only be able
857 to point to the single [XP]COM-correct |nsISupports| instance within an object; extra
858 querying ensues. Clients need to be able to pass around arbitrary interface pointers,
859 without hassles, through intermediary code that doesn't know the exact type.
862 NS_SPECIALIZE_TEMPLATE
863 class nsCOMPtr
<nsISupports
>
864 : private nsCOMPtr_base
867 typedef nsISupports element_type
;
873 // default constructor
875 NSCAP_LOG_ASSIGNMENT(this, 0);
878 nsCOMPtr( const nsCOMPtr
<nsISupports
>& aSmartPtr
)
879 : nsCOMPtr_base(aSmartPtr
.mRawPtr
)
883 NSCAP_ADDREF(this, mRawPtr
);
884 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
887 nsCOMPtr( nsISupports
* aRawPtr
)
888 : nsCOMPtr_base(aRawPtr
)
889 // construct from a raw pointer (of the right type)
892 NSCAP_ADDREF(this, mRawPtr
);
893 NSCAP_LOG_ASSIGNMENT(this, aRawPtr
);
896 nsCOMPtr( const already_AddRefed
<nsISupports
>& aSmartPtr
)
897 : nsCOMPtr_base(aSmartPtr
.mRawPtr
)
898 // construct from |dont_AddRef(expr)|
900 NSCAP_LOG_ASSIGNMENT(this, aSmartPtr
.mRawPtr
);
903 nsCOMPtr( const nsQueryInterface qi
)
905 // assign from |do_QueryInterface(expr)|
907 NSCAP_LOG_ASSIGNMENT(this, 0);
908 assign_from_qi(qi
, NS_GET_IID(nsISupports
));
911 nsCOMPtr( const nsQueryInterfaceWithError
& qi
)
913 // assign from |do_QueryInterface(expr, &rv)|
915 NSCAP_LOG_ASSIGNMENT(this, 0);
916 assign_from_qi_with_error(qi
, NS_GET_IID(nsISupports
));
919 nsCOMPtr( const nsGetServiceByCID gs
)
921 // assign from |do_GetService(cid_expr)|
923 NSCAP_LOG_ASSIGNMENT(this, 0);
924 assign_from_gs_cid(gs
, NS_GET_IID(nsISupports
));
927 nsCOMPtr( const nsGetServiceByCIDWithError
& gs
)
929 // assign from |do_GetService(cid_expr, &rv)|
931 NSCAP_LOG_ASSIGNMENT(this, 0);
932 assign_from_gs_cid_with_error(gs
, NS_GET_IID(nsISupports
));
935 nsCOMPtr( const nsGetServiceByContractID gs
)
937 // assign from |do_GetService(contractid_expr)|
939 NSCAP_LOG_ASSIGNMENT(this, 0);
940 assign_from_gs_contractid(gs
, NS_GET_IID(nsISupports
));
943 nsCOMPtr( const nsGetServiceByContractIDWithError
& gs
)
945 // assign from |do_GetService(contractid_expr, &rv)|
947 NSCAP_LOG_ASSIGNMENT(this, 0);
948 assign_from_gs_contractid_with_error(gs
, NS_GET_IID(nsISupports
));
951 nsCOMPtr( const nsCOMPtr_helper
& helper
)
953 // ...and finally, anything else we might need to construct from
954 // can exploit the |nsCOMPtr_helper| facility
956 NSCAP_LOG_ASSIGNMENT(this, 0);
957 assign_from_helper(helper
, NS_GET_IID(nsISupports
));
961 // Assignment operators
963 nsCOMPtr
<nsISupports
>&
964 operator=( const nsCOMPtr
<nsISupports
>& rhs
)
965 // copy assignment operator
967 assign_with_AddRef(rhs
.mRawPtr
);
971 nsCOMPtr
<nsISupports
>&
972 operator=( nsISupports
* rhs
)
973 // assign from a raw pointer (of the right type)
975 assign_with_AddRef(rhs
);
979 nsCOMPtr
<nsISupports
>&
980 operator=( const already_AddRefed
<nsISupports
>& rhs
)
981 // assign from |dont_AddRef(expr)|
983 assign_assuming_AddRef(rhs
.mRawPtr
);
987 nsCOMPtr
<nsISupports
>&
988 operator=( const nsQueryInterface rhs
)
989 // assign from |do_QueryInterface(expr)|
991 assign_from_qi(rhs
, NS_GET_IID(nsISupports
));
995 nsCOMPtr
<nsISupports
>&
996 operator=( const nsQueryInterfaceWithError
& rhs
)
997 // assign from |do_QueryInterface(expr, &rv)|
999 assign_from_qi_with_error(rhs
, NS_GET_IID(nsISupports
));
1003 nsCOMPtr
<nsISupports
>&
1004 operator=( const nsGetServiceByCID rhs
)
1005 // assign from |do_GetService(cid_expr)|
1007 assign_from_gs_cid(rhs
, NS_GET_IID(nsISupports
));
1011 nsCOMPtr
<nsISupports
>&
1012 operator=( const nsGetServiceByCIDWithError
& rhs
)
1013 // assign from |do_GetService(cid_expr, &rv)|
1015 assign_from_gs_cid_with_error(rhs
, NS_GET_IID(nsISupports
));
1019 nsCOMPtr
<nsISupports
>&
1020 operator=( const nsGetServiceByContractID rhs
)
1021 // assign from |do_GetService(contractid_expr)|
1023 assign_from_gs_contractid(rhs
, NS_GET_IID(nsISupports
));
1027 nsCOMPtr
<nsISupports
>&
1028 operator=( const nsGetServiceByContractIDWithError
& rhs
)
1029 // assign from |do_GetService(contractid_expr, &rv)|
1031 assign_from_gs_contractid_with_error(rhs
, NS_GET_IID(nsISupports
));
1035 nsCOMPtr
<nsISupports
>&
1036 operator=( const nsCOMPtr_helper
& rhs
)
1037 // ...and finally, anything else we might need to assign from
1038 // can exploit the |nsCOMPtr_helper| facility.
1040 assign_from_helper(rhs
, NS_GET_IID(nsISupports
));
1045 swap( nsCOMPtr
<nsISupports
>& rhs
)
1046 // ...exchange ownership with |rhs|; can save a pair of refcount operations
1048 nsISupports
* temp
= rhs
.mRawPtr
;
1049 NSCAP_LOG_ASSIGNMENT(&rhs
, mRawPtr
);
1050 NSCAP_LOG_ASSIGNMENT(this, temp
);
1051 NSCAP_LOG_RELEASE(this, mRawPtr
);
1052 NSCAP_LOG_RELEASE(&rhs
, temp
);
1053 rhs
.mRawPtr
= mRawPtr
;
1058 swap( nsISupports
*& rhs
)
1059 // ...exchange ownership with |rhs|; can save a pair of refcount operations
1061 nsISupports
* temp
= rhs
;
1062 NSCAP_LOG_ASSIGNMENT(this, temp
);
1063 NSCAP_LOG_RELEASE(this, mRawPtr
);
1069 forget( nsISupports
** rhs
)
1070 // Set the target of rhs to the value of mRawPtr and null out mRawPtr.
1071 // Useful to avoid unnecessary AddRef/Release pairs with "out"
1074 NS_ASSERTION(rhs
, "Null pointer passed to forget!");
1079 // Other pointer operators
1084 Prefer the implicit conversion provided automatically by
1085 |operator nsISupports*() const|.
1086 Use |get()| to resolve ambiguity or to get a castable pointer.
1089 return reinterpret_cast<nsISupports
*>(mRawPtr
);
1092 operator nsISupports
*() const
1094 ...makes an |nsCOMPtr| act like its underlying raw pointer type whenever it
1095 is used in a context where a raw pointer is expected. It is this operator
1096 that makes an |nsCOMPtr| substitutable for a raw pointer.
1098 Prefer the implicit use of this operator to calling |get()|, except where
1099 necessary to resolve ambiguity.
1108 NS_PRECONDITION(mRawPtr
!= 0, "You can't dereference a NULL nsCOMPtr with operator->().");
1112 #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY
1113 // broken version for IRIX
1115 nsCOMPtr
<nsISupports
>*
1117 // This is not intended to be used by clients. See |address_of|
1120 return const_cast<nsCOMPtr
<nsISupports
>*>(this);
1123 #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY
1125 nsCOMPtr
<nsISupports
>*
1127 // This is not intended to be used by clients. See |address_of|
1133 const nsCOMPtr
<nsISupports
>*
1135 // This is not intended to be used by clients. See |address_of|
1141 #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY
1148 NS_PRECONDITION(mRawPtr
!= 0, "You can't dereference a NULL nsCOMPtr with operator*().");
1155 #ifndef NSCAP_FEATURE_INLINE_STARTASSIGNMENT
1156 return reinterpret_cast<nsISupports
**>(begin_assignment());
1158 assign_assuming_AddRef(0);
1159 return reinterpret_cast<nsISupports
**>(&mRawPtr
);
1164 #ifndef NSCAP_FEATURE_USE_BASE
1167 nsCOMPtr
<T
>::assign_with_AddRef( nsISupports
* rawPtr
)
1170 NSCAP_ADDREF(this, rawPtr
);
1171 assign_assuming_AddRef(reinterpret_cast<T
*>(rawPtr
));
1176 nsCOMPtr
<T
>::assign_from_qi( const nsQueryInterface qi
, const nsIID
& aIID
)
1179 if ( NS_FAILED( qi(aIID
, &newRawPtr
) ) )
1181 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1186 nsCOMPtr
<T
>::assign_from_qi_with_error( const nsQueryInterfaceWithError
& qi
, const nsIID
& aIID
)
1189 if ( NS_FAILED( qi(aIID
, &newRawPtr
) ) )
1191 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1196 nsCOMPtr
<T
>::assign_from_gs_cid( const nsGetServiceByCID gs
, const nsIID
& aIID
)
1199 if ( NS_FAILED( gs(aIID
, &newRawPtr
) ) )
1201 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1206 nsCOMPtr
<T
>::assign_from_gs_cid_with_error( const nsGetServiceByCIDWithError
& gs
, const nsIID
& aIID
)
1209 if ( NS_FAILED( gs(aIID
, &newRawPtr
) ) )
1211 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1216 nsCOMPtr
<T
>::assign_from_gs_contractid( const nsGetServiceByContractID gs
, const nsIID
& aIID
)
1219 if ( NS_FAILED( gs(aIID
, &newRawPtr
) ) )
1221 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1226 nsCOMPtr
<T
>::assign_from_gs_contractid_with_error( const nsGetServiceByContractIDWithError
& gs
, const nsIID
& aIID
)
1229 if ( NS_FAILED( gs(aIID
, &newRawPtr
) ) )
1231 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1236 nsCOMPtr
<T
>::assign_from_helper( const nsCOMPtr_helper
& helper
, const nsIID
& aIID
)
1239 if ( NS_FAILED( helper(aIID
, &newRawPtr
) ) )
1241 assign_assuming_AddRef(static_cast<T
*>(newRawPtr
));
1246 nsCOMPtr
<T
>::begin_assignment()
1248 assign_assuming_AddRef(0);
1249 union { T
** mT
; void** mVoid
; } result
;
1250 result
.mT
= &mRawPtr
;
1251 return result
.mVoid
;
1255 #ifdef CANT_RESOLVE_CPP_CONST_AMBIGUITY
1257 // This is the broken version for IRIX, which can't handle the version below.
1262 address_of( const nsCOMPtr
<T
>& aPtr
)
1264 return aPtr
.get_address();
1267 #else // CANT_RESOLVE_CPP_CONST_AMBIGUITY
1272 address_of( nsCOMPtr
<T
>& aPtr
)
1274 return aPtr
.get_address();
1280 address_of( const nsCOMPtr
<T
>& aPtr
)
1282 return aPtr
.get_address();
1285 #endif // CANT_RESOLVE_CPP_CONST_AMBIGUITY
1288 class nsGetterAddRefs
1292 This class is designed to be used for anonymous temporary objects in the
1293 argument list of calls that return COM interface pointers, e.g.,
1295 nsCOMPtr<IFoo> fooP;
1296 ...->QueryInterface(iid, getter_AddRefs(fooP))
1298 DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. Use |getter_AddRefs()| instead.
1300 When initialized with a |nsCOMPtr|, as in the example above, it returns
1301 a |void**|, a |T**|, or an |nsISupports**| as needed, that the outer call (|QueryInterface| in this
1304 This type should be a nested class inside |nsCOMPtr<T>|.
1309 nsGetterAddRefs( nsCOMPtr
<T
>& aSmartPtr
)
1310 : mTargetSmartPtr(aSmartPtr
)
1312 // nothing else to do
1315 #if defined(NSCAP_FEATURE_TEST_DONTQUERY_CASES) || defined(NSCAP_LOG_EXTERNAL_ASSIGNMENT)
1318 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1319 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void *>(address_of(mTargetSmartPtr
)), mTargetSmartPtr
.get());
1322 #ifdef NSCAP_FEATURE_TEST_DONTQUERY_CASES
1323 mTargetSmartPtr
.Assert_NoQueryNeeded();
1330 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
1333 operator nsISupports
**()
1335 return reinterpret_cast<nsISupports
**>(mTargetSmartPtr
.StartAssignment());
1340 return mTargetSmartPtr
.StartAssignment();
1346 return *(mTargetSmartPtr
.StartAssignment());
1350 nsCOMPtr
<T
>& mTargetSmartPtr
;
1354 NS_SPECIALIZE_TEMPLATE
1355 class nsGetterAddRefs
<nsISupports
>
1359 nsGetterAddRefs( nsCOMPtr
<nsISupports
>& aSmartPtr
)
1360 : mTargetSmartPtr(aSmartPtr
)
1362 // nothing else to do
1365 #ifdef NSCAP_LOG_EXTERNAL_ASSIGNMENT
1368 NSCAP_LOG_ASSIGNMENT(reinterpret_cast<void *>(address_of(mTargetSmartPtr
)), mTargetSmartPtr
.get());
1374 return reinterpret_cast<void**>(mTargetSmartPtr
.StartAssignment());
1377 operator nsISupports
**()
1379 return mTargetSmartPtr
.StartAssignment();
1385 return *(mTargetSmartPtr
.StartAssignment());
1389 nsCOMPtr
<nsISupports
>& mTargetSmartPtr
;
1396 getter_AddRefs( nsCOMPtr
<T
>& aSmartPtr
)
1398 Used around a |nsCOMPtr| when
1399 ...makes the class |nsGetterAddRefs<T>| invisible.
1402 return nsGetterAddRefs
<T
>(aSmartPtr
);
1407 // Comparing two |nsCOMPtr|s
1409 template <class T
, class U
>
1412 operator==( const nsCOMPtr
<T
>& lhs
, const nsCOMPtr
<U
>& rhs
)
1414 return static_cast<const T
*>(lhs
.get()) == static_cast<const U
*>(rhs
.get());
1418 template <class T
, class U
>
1421 operator!=( const nsCOMPtr
<T
>& lhs
, const nsCOMPtr
<U
>& rhs
)
1423 return static_cast<const T
*>(lhs
.get()) != static_cast<const U
*>(rhs
.get());
1427 // Comparing an |nsCOMPtr| to a raw pointer
1429 template <class T
, class U
>
1432 operator==( const nsCOMPtr
<T
>& lhs
, const U
* rhs
)
1434 return static_cast<const T
*>(lhs
.get()) == rhs
;
1437 template <class T
, class U
>
1440 operator==( const U
* lhs
, const nsCOMPtr
<T
>& rhs
)
1442 return lhs
== static_cast<const T
*>(rhs
.get());
1445 template <class T
, class U
>
1448 operator!=( const nsCOMPtr
<T
>& lhs
, const U
* rhs
)
1450 return static_cast<const T
*>(lhs
.get()) != rhs
;
1453 template <class T
, class U
>
1456 operator!=( const U
* lhs
, const nsCOMPtr
<T
>& rhs
)
1458 return lhs
!= static_cast<const T
*>(rhs
.get());
1461 // To avoid ambiguities caused by the presence of builtin |operator==|s
1462 // creating a situation where one of the |operator==| defined above
1463 // has a better conversion for one argument and the builtin has a
1464 // better conversion for the other argument, define additional
1465 // |operator==| without the |const| on the raw pointer.
1466 // See bug 65664 for details.
1468 // This is defined by an autoconf test, but VC++ also has a bug that
1469 // prevents us from using these. (It also, fortunately, has the bug
1470 // that we don't need them either.)
1471 #if defined(_MSC_VER) && (_MSC_VER < 1310)
1472 #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ
1473 #define NSCAP_DONT_PROVIDE_NONCONST_OPEQ
1477 #ifndef NSCAP_DONT_PROVIDE_NONCONST_OPEQ
1478 template <class T
, class U
>
1481 operator==( const nsCOMPtr
<T
>& lhs
, U
* rhs
)
1483 return static_cast<const T
*>(lhs
.get()) == const_cast<const U
*>(rhs
);
1486 template <class T
, class U
>
1489 operator==( U
* lhs
, const nsCOMPtr
<T
>& rhs
)
1491 return const_cast<const U
*>(lhs
) == static_cast<const T
*>(rhs
.get());
1494 template <class T
, class U
>
1497 operator!=( const nsCOMPtr
<T
>& lhs
, U
* rhs
)
1499 return static_cast<const T
*>(lhs
.get()) != const_cast<const U
*>(rhs
);
1502 template <class T
, class U
>
1505 operator!=( U
* lhs
, const nsCOMPtr
<T
>& rhs
)
1507 return const_cast<const U
*>(lhs
) != static_cast<const T
*>(rhs
.get());
1513 // Comparing an |nsCOMPtr| to |0|
1520 operator==( const nsCOMPtr
<T
>& lhs
, NSCAP_Zero
* rhs
)
1521 // specifically to allow |smartPtr == 0|
1523 return static_cast<const void*>(lhs
.get()) == reinterpret_cast<const void*>(rhs
);
1529 operator==( NSCAP_Zero
* lhs
, const nsCOMPtr
<T
>& rhs
)
1530 // specifically to allow |0 == smartPtr|
1532 return reinterpret_cast<const void*>(lhs
) == static_cast<const void*>(rhs
.get());
1538 operator!=( const nsCOMPtr
<T
>& lhs
, NSCAP_Zero
* rhs
)
1539 // specifically to allow |smartPtr != 0|
1541 return static_cast<const void*>(lhs
.get()) != reinterpret_cast<const void*>(rhs
);
1547 operator!=( NSCAP_Zero
* lhs
, const nsCOMPtr
<T
>& rhs
)
1548 // specifically to allow |0 != smartPtr|
1550 return reinterpret_cast<const void*>(lhs
) != static_cast<const void*>(rhs
.get());
1554 #ifdef HAVE_CPP_TROUBLE_COMPARING_TO_ZERO
1556 // We need to explicitly define comparison operators for `int'
1557 // because the compiler is lame.
1562 operator==( const nsCOMPtr
<T
>& lhs
, int rhs
)
1563 // specifically to allow |smartPtr == 0|
1565 return static_cast<const void*>(lhs
.get()) == reinterpret_cast<const void*>(rhs
);
1571 operator==( int lhs
, const nsCOMPtr
<T
>& rhs
)
1572 // specifically to allow |0 == smartPtr|
1574 return reinterpret_cast<const void*>(lhs
) == static_cast<const void*>(rhs
.get());
1577 #endif // !defined(HAVE_CPP_TROUBLE_COMPARING_TO_ZERO)
1579 // Comparing any two [XP]COM objects for identity
1583 SameCOMIdentity( nsISupports
* lhs
, nsISupports
* rhs
)
1585 return nsCOMPtr
<nsISupports
>( do_QueryInterface(lhs
) ) == nsCOMPtr
<nsISupports
>( do_QueryInterface(rhs
) );
1590 template <class SourceType
, class DestinationType
>
1593 CallQueryInterface( nsCOMPtr
<SourceType
>& aSourcePtr
, DestinationType
** aDestPtr
)
1595 return CallQueryInterface(aSourcePtr
.get(), aDestPtr
);
1598 #endif // !defined(nsCOMPtr_h___)