getter_AddRefs and friends (Re: nsCOMPtr questions)
Document Status: Retired.
This document is now obsolete.
Coincidentally, the information in this document is mostly accurate.
The only change is that one can, again,
initialize from or assign raw [XP]COM interface pointers
into an an nsCOMPtr.
This is a synonym for saying dont_QueryInterface().
Please use the
nsCOMPtr User's Manual
as your reference.
getter_AddRefs
and alternatives.
It is a followup to this message.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
One thing to note about my previous message is that the examples were
slightly simplified for the purpose of expounding on |getter_AddRef|s.
In reality, the first two example assignments aren't actually legal.
// Good for talking about |AddRef| but not actually legal...
nsCOMPtr<X> x1 = aRawX;
// ...
nsCOMPtr<X> x2 = CreateAnX();
// Oops!...
You aren't allowed to assign a raw pointer _directly_ into an
|nsCOMPtr| without saying whether you will allow |QueryInterface| to
be called. In both these cases, we don't need |QueryInterface| since
|aRawX| is supposedly of the exact right type, and |CreateAnX()|
produces a value of the exact right type. So we would actually say:
nsCOMPtr<X> x1 = dont_QueryInterface( aRawX );
nsCOMPtr<X> x2 = dont_QueryInterface( CreateAnX() );
The functions available for this role are
do_QueryInterface( X* );
// the pointer is |QueryInterface|d for the COM correct interface,
// and it is |AddRef|ed (by |QueryInterface|) as part of the
// assignment. Use this when the type you are assigning is is
// different than your |nsCOMPtr|, e.g.,
Y* y;
// ...
nsCOMPtr<X> x = do_QueryInterace(y);
do_QueryInterface( X*, nsresult* );
// as above, but the error result of |QueryInterface| is available
// to you, e.g.,
nsresult status;
nsCOMPtr<X> x = do_QueryInterface(y, &status);
if ( NS_SUCCEEDED(status) )
// ...
dont_QueryInterface( X* );
// the minimal action: my pointer is exactly the right type, I
// PROMISE. So just assign it in. It _will_ be |AddRef|ed,
// e.g.,
X* x;
// ...
nsCOMPtr<X> x = dont_QueryInterface(x);
// Note, this is not appropriate for inheritance, e.g.,
class X { ... };
class Z : public X { ... };
Z* z;
// ...
nsCOMPtr<X> x = dont_QueryInterface(z);
// Wrong! The |X| that C++ extracts from this instance may not
// be the one |QueryInterface| would give you. You must use
// |do_QueryInterface|
nsCOMPtr<X> x = do_QueryInterface(z); // Right!
getter_AddRefs( X* );
// the _really_ minimal action: my pointer is exactly the right
// type, I PROMISE. So just assign it in. And by the way, the
// thing that made the pointer already |AddRef|ed it for you.
// E.g.,
X* CreateAnX();
// ...
nsCOMPtr<X> x = getter_AddRefs( CreateAnX() );
dont_AddRef( X* );
// A deprecated synonym for |getter_AddRefs()| in case you happen
// to see it in code.
This chart summarizes the calls
|AddRef| don't |AddRef|
---------------------------------------------
allow QI |do_QueryInterface| ???
don't allow QI |dont_QueryInterface| |getter_AddRefs|
So what do you do if you have to apply more than one of these? Well
the only combination that you don't get `out of the box' (see the
chart above) is when you want to |QueryInterface|, but you _don't_
want to |AddRef|. E.g., in this situation:
Z* CreateAZ();
// ...
nsCOMPtr<X> x = ???
Well, you can't really mix those two because in COM it is _interfaces_
not objects that are ref-counted. Ergo, you must say:
Z* CreateAZ();
// ...
nsCOMPtr<Z> z = getter_AddRefs( CreateAZ() ); //
nsCOMPtr<X> x = do_QueryInterface(z);
...and in fact, if you don't otherwise need to keep the |Z| around,
you can contain its life with
nsCOMPtr<X> x;
{
nsCOMPtr<Z> z = getter_AddRefs( CreateAZ() );
x = do_QueryInterface(z);
}
...and if our compilers were better on the marginal platforms, you
could even reduce it to
nsCOMPtr<X> x = do_QueryInterface(
nsCOMPtr<Z>( getter_AddRefs(CreateAZ()) )
);
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/AwUBNx9wi/GmojMuVn+fEQJ8WgCeJktjSOeFAngObqS2gaX0jM2QrW0AoJSB
7iMGA0my9dV5ZirRmsIKJQ4p
=cOVU
-----END PGP SIGNATURE-----