getter_doesnt_AddRef is gone (Re: nsCOMPtr questions)
Document Status: Retired.
This document is now obsolete.
Coincidentally, as of 25 October 1999, the information in it is still accurate.
However, please use the
nsCOMPtr User's Manual
as your reference.
getter_AddRefs,
the now illegal getter_doesnt_AddRef,
and some esoterica about services.
There is a followup message.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
|getter_doesnt_AddRef| no longer exists. It no longer exists because
it is a rule of COM (and hence XPCOM) that all `getter' functions
_must_ AddRef the interface pointer they produce before returning it.
A getter is any function that yields a COM interface pointer (either
as it's actual result or through a parameter). The prototypical case
is:
class Foo
{
public:
nsresult GetX( X** ); // a `getter' (in the standard form)
// nsresult SetX( X* ); // a `setter'
X* GetX(); // a non-standard getter
private:
X* mX;
};
Note also that by this definition factory functions are also getters.
|nsComponentManager::CreateInstance| is a (factory function style)
`getter'.
Normally, when you assign a COM interface pointer into an |nsCOMPtr|
variable, the |nsCOMPtr| is responsible for |AddRef|ing the interface.
However, like all good `getter's,
|nsComponentManager::CreateInstance| |AddRef|s its result (the created
component), therefore, when giving it an |nsCOMPtr| argument to store
that result in, you must tell the |nsCOMPtr| that the getter function
(CreateInstance, here) will do the |AddRef|, not the |nsCOMPtr|
itself.
Here are some examples:
X* aRawX;
nsresult CreateAnX( X** result );
X* CreateAnX(); // Note, like all `getters' |CreateAnX()|
// |AddRef|s its result (in both forms)
nsCOMPtr<X> x1 = aRawX;
// An |nsCOMPtr| automatically |AddRef|s
// when you assign into it.
// That's good, here.
nsCOMPtr<X> x2 = CreateAnX();
// Oops! the |nsCOMPtr| automatically
// |AddRef|s, _and_ |CreateAnX()| |AddRef|s
// Leak!!
nsCOMPtr<X> x3 = getter_AddRefs( CreateAnX() );
// Tell the |nsCOMPtr| _not_ to |AddRef|,
// Now only |CreateAnX()| |AddRef|s
// No more Leak
nsCOMPtr<X> x4;
nsresult status = CreateAnX( getter_AddRefs(x4) );
// |CreateAnX()| will assign into |x4|,
// so tell |x4| _not_ to |AddRef|
// since |CreateAnX()| already calls |AddRef|
This makes the answer easy for your _component_ statement:
nsCOMPtr<nsIDataFlavor> flavor;
nsresult rv = nsComponentManager::CreateInstance(kCDataFlavorCID,
0,
kIDataFlavorIID,
getter_AddRefs(flavor));
I use a template function (that I have not checked in yet) to make
this scenario simpler. This is the function:
template <class T>
inline
nsresult
CreateComponent( const nsCID& cid,
nsCOMPtr<T>* created_component,
nsISupports* delegate = 0 )
{
assert(created_component);
return nsComponentManager::CreateInstance(cid,
delegate,
T::GetIID(),
getter_AddRefs(*created_component));
}
This reduces the code you would write to:
nsCOMPtr<nsIDataFlavor> flavor;
nsresult rv = CreateComponent(kCDataFlavorCID, &flavor);
The problem with services, however, is that you don't |AddRef| and
|Release| them. For that reason, you wouldn't, at least currently,
want to use an |nsCOMPtr| to manage |AddRef|s and |Release|s on them.
You acquire an interest in a service with |GetService|, and release
that interest with |ReleaseService|. |AddRef| and |Release| don't
come into it. Unless this changes, don't use |nsCOMPtr|s to hold
references to services.
Hope this helps,
______________________________________________________________________
Scott Collins <http://www.meer.net/ScottCollins?Netscape>
-----BEGIN PGP SIGNATURE-----
Version: PGP Personal Privacy 6.0.2
Comment: get my key at <http://www.meer.net/ScottCollins/#key>
iQA/AwUBNx9mEvGmojMuVn+fEQJSagCgqDlafzoK5kSE29iNJ5ubED1/qHQAoL/T
ZVq0h8RqfWo3Zmcys37uT6PQ
=w15I
-----END PGP SIGNATURE-----