getter_AddRefs and friends (Re: nsCOMPtr questions)

by Scott Collins

last modified 25 October 1999

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.

Abstract: An email message that describes getter_AddRefs and alternatives. It is a followup to this message.

The 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-----

Valid HTML 4.0! CSS Copyright© 1999 by Netscape; use is subject to the NPL.