📄 nscomptr.h
字号:
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* ***** BEGIN LICENSE BLOCK ***** * Version: NPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Netscape Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Scott Collins <scc@mozilla.org> (original author) * L. David Baron <dbaron@dbaron.org> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the NPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the NPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */#ifndef nsCOMPtr_h___#define nsCOMPtr_h___/* Having problems? See the User Manual at: http://www.mozilla.org/projects/xpcom/nsCOMPtr.html nsCOMPtr better than a raw pointer for owning objects -- scc*/ // Wrapping includes can speed up compiles (see "Large Scale C++ Software Design")#ifndef nsDebug_h___#include "nsDebug.h" // for |NS_PRECONDITION|#endif#ifndef nsISupportsUtils_h__#include "nsISupportsUtils.h" // for |nsresult|, |NS_ADDREF|, |NS_GET_IID| et al#endif#ifndef nscore_h___#include "nscore.h" // for |NS_..._CAST|, |NS_COM|#endif/* WARNING: This file defines several macros for internal use only. These macros begin with the prefix |NSCAP_|. Do not use these macros in your own code. They are for internal use only for cross-platform compatibility, and are subject to change without notice.*/#ifdef _MSC_VER #define NSCAP_FEATURE_INLINE_STARTASSIGNMENT // under VC++, we win by inlining StartAssignment // Also under VC++, at the highest warning level, we are overwhelmed with warnings // about (unused) inline functions being removed. This is to be expected with // templates, so we disable the warning. #pragma warning( disable: 4514 )#endif#define NSCAP_FEATURE_FACTOR_DESTRUCTOR#ifdef NS_DEBUG #define NSCAP_FEATURE_TEST_DONTQUERY_CASES #define NSCAP_FEATURE_DEBUG_PTR_TYPES//#define NSCAP_FEATURE_TEST_NONNULL_QUERY_SUCCEEDS#endif /* |...TEST_DONTQUERY_CASES| and |...DEBUG_PTR_TYPES| introduce some code that is problematic on a select few of our platforms, e.g., QNX. Therefore, I'm providing a mechanism by which these features can be explicitly disabled from the command-line. */#ifdef NSCAP_DISABLE_TEST_DONTQUERY_CASES #undef NSCAP_FEATURE_TEST_DONTQUERY_CASES#endif#if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES) || !defined(NS_DEBUG) #undef NSCAP_FEATURE_DEBUG_PTR_TYPES#endif#ifdef NSCAP_FEATURE_DEBUG_PTR_TYPES #undef NSCAP_FEATURE_FACTOR_DESTRUCTOR#endif#ifdef HAVE_CPP_BOOL typedef bool NSCAP_BOOL;#else typedef PRBool NSCAP_BOOL;#endif /* The following three macros (|NSCAP_ADDREF|, |NSCAP_RELEASE|, and |NSCAP_LOG_ASSIGNMENT|) allow external clients the ability to add logging or other interesting debug facilities. In fact, if you want |nsCOMPtr| to participate in the standard logging facility, you provide (e.g., in "nsTraceRefcnt.h") suitable definitions #define NSCAP_ADDREF(this, ptr) NS_ADDREF(ptr) #define NSCAP_RELEASE(this, ptr) NS_RELEASE(ptr) */#ifndef NSCAP_ADDREF #define NSCAP_ADDREF(this, ptr) (ptr)->AddRef()#endif#ifndef NSCAP_RELEASE #define NSCAP_RELEASE(this, ptr) (ptr)->Release()#endif // Clients can define |NSCAP_LOG_ASSIGNMENT| to perform logging.#ifdef NSCAP_LOG_ASSIGNMENT // Remember that |NSCAP_LOG_ASSIGNMENT| was defined by some client so that we know // to instantiate |~nsGetterAddRefs| in turn to note the external assignment into // the |nsCOMPtr|. #define NSCAP_LOG_EXTERNAL_ASSIGNMENT#else // ...otherwise, just strip it out of the code #define NSCAP_LOG_ASSIGNMENT(this, ptr)#endif#ifndef NSCAP_LOG_RELEASE #define NSCAP_LOG_RELEASE(this, ptr)#endif /* WARNING: VC++4.2 is very picky. To compile under VC++4.2, the classes must be defined in an order that satisfies: nsDerivedSafe < nsCOMPtr already_AddRefed < nsCOMPtr nsCOMPtr < nsGetterAddRefs The other compilers probably won't complain, so please don't reorder these classes, on pain of breaking 4.2 compatibility. */template <class T>class nsDerivedSafe : public T /* No client should ever see or have to type the name of this class. It is the artifact that makes it a compile-time error to call |AddRef| and |Release| on a |nsCOMPtr|. DO NOT USE THIS TYPE DIRECTLY IN YOUR CODE. See |nsCOMPtr::operator->|, |nsCOMPtr::operator*|, et al. This type should be a nested class inside |nsCOMPtr<T>|. */ { private:#ifdef HAVE_CPP_ACCESS_CHANGING_USING using T::AddRef; using T::Release;#else nsrefcnt AddRef(void); nsrefcnt Release(void);#endif#if !defined(XP_OS2_VACPP) && !defined(AIX) && !defined(IRIX) void operator delete( void*, size_t ); // NOT TO BE IMPLEMENTED // declaring |operator delete| private makes calling delete on an interface pointer a compile error#endif nsDerivedSafe<T>& operator=( const T& ); // NOT TO BE IMPLEMENTED // you may not call |operator=()| through a dereferenced |nsCOMPtr|, because you'd get the wrong one /* Compiler warnings and errors: nsDerivedSafe operator=() hides inherited operator=(). If you see that, that means somebody checked in a [XP]COM interface class that declares an |operator=()|, and that's _bad_. So bad, in fact, that this declaration exists explicitly to stop people from doing it. */ };#if !defined(HAVE_CPP_ACCESS_CHANGING_USING) && defined(NEED_CPP_UNUSED_IMPLEMENTATIONS)template <class T>nsrefcntnsDerivedSafe<T>::AddRef() { return 0; }template <class T>nsrefcntnsDerivedSafe<T>::Release() { return 0; }#endiftemplate <class T>struct already_AddRefed /* ...cooperates with |nsCOMPtr| to allow you to assign in a pointer _without_ |AddRef|ing it. You might want to use this as a return type from a function that produces an already |AddRef|ed pointer as a result. See also |getter_AddRefs()|, |dont_AddRef()|, and |class nsGetterAddRefs|. This type should be a nested class inside |nsCOMPtr<T>|. Yes, |already_AddRefed| could have been implemented as an |nsCOMPtr_helper| to avoid adding specialized machinery to |nsCOMPtr| ... but this is the simplest case, and perhaps worth the savings in time and space that its specific implementation affords over the more general solution offered by |nsCOMPtr_helper|. */ { already_AddRefed( T* aRawPtr ) : mRawPtr(aRawPtr) { // nothing else to do here } T* get() const { return mRawPtr; } T* mRawPtr; };template <class T>inlineconst already_AddRefed<T>getter_AddRefs( T* aRawPtr ) /* ...makes typing easier, because it deduces the template type, e.g., you write |dont_AddRef(fooP)| instead of |already_AddRefed<IFoo>(fooP)|. */ { return already_AddRefed<T>(aRawPtr); }template <class T>inlineconst already_AddRefed<T>getter_AddRefs( const already_AddRefed<T> aAlreadyAddRefedPtr ) { return aAlreadyAddRefedPtr; }template <class T>inlineconst already_AddRefed<T>dont_AddRef( T* aRawPtr ) { return already_AddRefed<T>(aRawPtr); }template <class T>inlineconst already_AddRefed<T>dont_AddRef( const already_AddRefed<T> aAlreadyAddRefedPtr ) { return aAlreadyAddRefedPtr; } /* There used to be machinery to allow |dont_QueryInterface()| to work, but since it is now equivalent to using a raw pointer ... all that machinery has gone away. For pointer arguments, the following definition should optimize away. This is better than using a |#define| because it is scoped. */template <class T>inlineT*dont_QueryInterface( T* expr ) { return expr; }class nsCOMPtr_helper /* An |nsCOMPtr_helper| transforms commonly called getters into typesafe forms that are more convenient to call, and more efficient to use with |nsCOMPtr|s. Good candidates for helpers are |QueryInterface()|, |CreateInstance()|, etc. Here are the rules for a helper: - it implements |operator()| to produce an interface pointer - (except for its name) |operator()| is a valid [XP]COM `getter' - the interface pointer that it returns is already |AddRef()|ed (as from any good getter) - it matches the type requested with the supplied |nsIID| argument - its constructor provides an optional |nsresult*| that |operator()| can fill in with an error when it is executed See |class nsQueryInterface| for an example. */ { public: virtual nsresult operator()( const nsIID&, void** ) const = 0; };class NS_COM nsQueryInterface : public nsCOMPtr_helper { public: nsQueryInterface( nsISupports* aRawPtr, nsresult* error ) : mRawPtr(aRawPtr), mErrorPtr(error) { // nothing else to do here } virtual nsresult operator()( const nsIID& aIID, void** ) const; private: nsISupports* mRawPtr; nsresult* mErrorPtr; };inlineconst nsQueryInterfacedo_QueryInterface( nsISupports* aRawPtr, nsresult* error = 0 ) { return nsQueryInterface(aRawPtr, error); }template <class T>inlinevoiddo_QueryInterface( already_AddRefed<T>& ) { // This signature exists soley to _stop_ you from doing the bad thing. // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by // someone else is an automatic leak. See <http://bugzilla.mozilla.org/show_bug.cgi?id=8221>. }template <class T>inlinevoiddo_QueryInterface( already_AddRefed<T>&, nsresult* ) { // This signature exists soley to _stop_ you from doing the bad thing. // Saying |do_QueryInterface()| on a pointer that is not otherwise owned by // someone else is an automatic leak. See <http://bugzilla.mozilla.org/show_bug.cgi?id=8221>. }class nsCOMPtr_base /* ...factors implementation for all template versions of |nsCOMPtr|. This should really be an |nsCOMPtr<nsISupports>|, but this wouldn't work because unlike the Here's the way people normally do things like this template <class T> class Foo { ... }; template <> class Foo<void*> { ... }; template <class T> class Foo<T*> : private Foo<void*> { ... }; */ { public: nsCOMPtr_base( nsISupports* rawPtr = 0 ) : mRawPtr(rawPtr) { // nothing else to do here }#ifdef NSCAP_FEATURE_FACTOR_DESTRUCTOR NS_COM ~nsCOMPtr_base();#else // Allow debug builds to link with optimized versions of nsCOMPtr-using // plugins (e.g., JVMs). NS_COM ~nsCOMPtr_base() { }#endif NS_COM void assign_with_AddRef( nsISupports* ); NS_COM void assign_from_helper( const nsCOMPtr_helper&, const nsIID& ); NS_COM void** begin_assignment(); protected: nsISupports* mRawPtr; void assign_assuming_AddRef( nsISupports* newPtr ) { /* |AddRef()|ing the new value (before entering this function) before |Release()|ing the old lets us safely ignore the self-assignment case. We must, however, be careful only to |Release()| _after_ doing the assignment, in case the |Release()| leads to our _own_ destruction, which would, in turn, cause an incorrect second |Release()| of our old pointer. Thank <waterson@netscape.com> for discovering this. */ nsISupports* oldPtr = mRawPtr; mRawPtr = newPtr; NSCAP_LOG_ASSIGNMENT(this, newPtr); NSCAP_LOG_RELEASE(this, oldPtr); if ( oldPtr ) NSCAP_RELEASE(this, oldPtr); } };// template <class T> class nsGetterAddRefs;template <class T>class nsCOMPtr#ifndef NSCAP_FEATURE_DEBUG_PTR_TYPES
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -