📄 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_USE_BASE
#ifdef NS_DEBUG
#define NSCAP_FEATURE_TEST_DONTQUERY_CASES
#undef NSCAP_FEATURE_USE_BASE
//#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 __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
// Our use of nsCOMPtr_base::mRawPtr violates the C++ standard's aliasing
// rules. Mark it with the may_alias attribute so that gcc 3.3 and higher
// don't reorder instructions based on aliasing assumptions for
// this variable. Fortunately, gcc versions < 3.3 do not do any
// optimizations that break nsCOMPtr.
#define NS_MAY_ALIAS_PTR(t) t* __attribute__((__may_alias__))
#else
#define NS_MAY_ALIAS_PTR(t) t*
#endif
#if defined(NSCAP_DISABLE_DEBUG_PTR_TYPES)
#define NSCAP_FEATURE_USE_BASE
#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(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.
*/
protected:
nsDerivedSafe(); // NOT TO BE IMPLEMENTED
/*
This ctor exists to avoid compile errors and warnings about nsDeriviedSafe using the
default ctor but inheriting classes without an empty ctor. See bug 209667.
*/
};
#if !defined(HAVE_CPP_ACCESS_CHANGING_USING) && defined(NEED_CPP_UNUSED_IMPLEMENTATIONS)
template <class T>
nsrefcnt
nsDerivedSafe<T>::AddRef()
{
return 0;
}
template <class T>
nsrefcnt
nsDerivedSafe<T>::Release()
{
return 0;
}
#endif
template <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>
inline
const 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>
inline
const already_AddRefed<T>
getter_AddRefs( const already_AddRefed<T> aAlreadyAddRefedPtr )
{
return aAlreadyAddRefedPtr;
}
template <class T>
inline
const already_AddRefed<T>
dont_AddRef( T* aRawPtr )
{
return already_AddRefed<T>(aRawPtr);
}
template <class T>
inline
const already_AddRefed<T>
dont_AddRef( const already_AddRefed<T> aAlreadyAddRefedPtr )
{
return aAlreadyAddRefedPtr;
}
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;
};
inline
const nsQueryInterface
do_QueryInterface( nsISupports* aRawPtr, nsresult* error = 0 )
{
return nsQueryInterface(aRawPtr, error);
}
template <class T>
inline
void
do_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>
inline
void
do_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
}
NS_COM ~nsCOMPtr_base();
NS_COM void assign_with_AddRef( nsISupports* );
NS_COM void assign_from_helper( const nsCOMPtr_helper&, const nsIID& );
NS_COM void** begin_assignment();
protected:
NS_MAY_ALIAS_PTR(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
#ifdef NSCAP_FEATURE_USE_BASE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -