The Complete nsCOMPtr User's Manual

by Scott Collins

last modified 9 November 1999

The latest public version of this document is available at

Please direct all comments and contributions to news:netscape.public.mozilla.xpcom and/or Scott Collins <scc@netscape.com>.

Status, Recent Changes, and Plans

I'm sorry this section is in the way for first-time readers. You may want to skip ahead to the table of contents, or directly to the Getting Started Guide, the Reference Manual, or the FAQ. I put this section at the top so that checking for recent changes will be easy.

Recent changes to nsCOMPtr

Most recent first

Plans for nsCOMPtr

Plans for this document

This document is not yet final. There are still sections that need to be filled in. Please send me any additions, omissions, corrections, changes, clarifications, etc., that you think this document needs. I want it to be useful as soon as possible.

Contents

This document is the sum total of everything written down about nsCOMPtr. It comprises three major parts:

If you have a question about nsCOMPtr, and this document doesn't answer it, there probably isn't a document that answers it. You'll have to turn to the xpcom newgroup, email me, or another experienced nsCOMPtr user, or find the answer by experimentation. I'll add new questions and answers to this document as they are asked, and I'll try to keep it in synch with nsCOMPtr's implementation as it changes.

If you've never used nsCOMPtr before, you're starting in the right place. Just keep reading. You'll know when to stop. After you've been using nsCOMPtrs for a while, and you reach unfamiliar territory, or run into compiler errors; you may want to return to this document to get help from the Reference Manual, or the FAQ.


Getting Started Guide

If you have never used nsCOMPtrs before, this section is for you. If you're already familiar with nsCOMPtrs, then you might want to skip ahead to the Reference Manual or the FAQ. Don't worry; the Getting Started Guide is short.

Introduction

What is nsCOMPtr?

nsCOMPtr is a tool to help prevent leaks.

nsCOMPtr is a `smart-pointer'. It is a template class that acts, syntactically, just like an ordinary pointer in C or C++, i.e., you can apply * or -> to it to `get to' what it points at. nsCOMPtr is smart in that, unlike a raw [XP]COM interface pointer, nsCOMPtr manages AddRef(), Release(), and QueryInterface() for you. nsCOMPtr is defined in the source files[#]:

...though you probably don't want to look in there, just yet.

With nsCOMPtr, you can write code that is shorter, cleaner, clearer, and safer, than you can with raw [XP]COM interface pointers.

[XP]COM Basics: Ownership and Reference Counting

This is a quick refresher on some fundamental issues of [XP]COM. You should already know this, and should be able to just skim this short section. If this is unfamiliar material, you're not ready for nsCOMPtrs yet. A good place to learn about the basic rules and reasoning behind COM is in Essential COM[#] by Don Box[#]. Don Box gets into more of the details, traps, and pitfalls of COM in Effective COM[#]. You should also have a reasonable knowledge of C++. Probably the three most helpful books on this topic are The C++ Programming Language[#] by Bjarne Stroustrup, Effective C++[#], and More Effective C++[#] by Scott Meyers.

All [XP]COM objects are allocated on the heap. Clients don't get to know much about the implementation of any such object. They reference it only through a pointer to an `interface', i.e., the static type of the pointer is a pointer to an abstract base class, the actual object pointed to is a class derived from that abstract base class. The [XP]COM object is said to `implement that interface'. The clients reference to the object is typically called `an interface pointer'.

An object may implement many interfaces. Each interface is (at least conceptually) separately `reference counted'. That is, the interface keeps a count of the number of clients holding references to it. When that count goes to zero, the interface may delete itself. Clients are expected to keep this reference count accurate by incrementing it when they acquire a reference to the interface, and decrementing it before they let go. To facilitate this, all interfaces inherit from an abstract base class that provides the member functions AddRef(), and Release().

A rule of [XP]COM is that any function that creates or returns an interface pointer will have already AddRef()ed it. The caller can then hold onto the reference indefinitely, calling Release() when it no longer needs it. When the last pointer to an interface is Release()d, the iterface (and consequently, typically the underlyting object) will delete itself. As long as there is an outstanding AddRef() against the interface, it continues to exist. If you forget to call Release(), the object will leak, i.e., the storage for that object will never be reclaimed. Leaks are bad :-).

A reference through which you will call AddRef() and Release() is called an owning reference. It holds a stake in the underlying object. That object cannot go away until the owning reference has relinquished its claim. Not all references need to be owning references. In fact, if two object somehow end up owning each other (even transitively) it becomes difficult for either of those object to be reclaimed without adding some `out-of-band' mechanism for breaking the ownership cycle. The document Some COM Ownership Guidelines[#] provides some hints on when ownership is needed. The following lists are good starting point, but by no means complete.

You use an owning reference when

You don't need an owning reference when

It turns out that reference counting by hand is hard for programmers to get right. It may sound simple, but in practice it's very easy to forget to Release() at the appropriate moment. Or to AddRef() too many or too few times.

How does nsCOMPtr help?

nsCOMPtr manages AddRef(), Release(), and other red-tape for you. An nsCOMPtr looks and acts as much like a raw [XP]COM interface pointer as C++ allows, but it knows it owns the object it points to. This takes a little getting used to on your part, but ends up with less typing, clearer, safer code, and less leaks.

For instance, here is a typical snippet of code (at its most compact) where you assign a [XP]COM interface pointer into a member variable, i.e., the body of a `setter' function, side-by-side using raw [XP]COM interface pointers and nsCOMPtrs.
Comparison 1. Setting a member variable.
// raw [XP]COM interface pointers...
// given: |nsIFoo* mFooPtr;|

/*
  |Release()| the old value, if any,
  before over-writing it (and therefore
  leaking it).

  Assign in the new value, and if it's
  not |NULL|, |AddRef()| it, since we'll
  be holding on to it for a while.
*/

NS_IF_RELEASE(mFooPtr);
if ( mFooPtr = aFooPtr )
  NS_ADDREF(mFooPtr);
// |nsCOMPtr|...
// given: |nsCOMPtr<nsIFoo> mFooPtr;|

/*
  This assignment automatically
  |Release()|s the old value in
  |mFooPtr|, if any, and |AddRef()|s the
  new one.
*/





mFooPtr = aFooPtr;

Additionally, the class using raw [XP]COM interface pointers will need a destructor to Release() mFooPtr; and a constructor to ensure that mFooPtr is initially set to NULL (or some other reasonable value).

nsCOMPtr helps you write code that is leak-proof, exception safe, and significantly less verbose than you would with raw [XP]COM interface pointers. With nsCOMPtr, you may never have to call AddRef(), Release(), or QueryInterface() by hand.

You still have to understand [XP]COM. You still have to know which functions return interface pointers that have already been AddRef()ed and which don't. You still have to ensure your program logic doesn't produce circularly referencing garbage. nsCOMPtr is not a panacea. It is, however, helpful, easy to use, well-tested, and polite. It doesn't require that a function author cooperate with you, nor does your use force others to use it.

Using nsCOMPtr

The Basics

In most cases, you'll use an nsCOMPtr exactly as you would a raw [XP]COM interface pointer. Note the slight difference in declaration.
Comparison 2. Similarities: nsCOMPtr is syntactically similar to raw [XP]COM interface pointers.
// raw [XP]COM interface pointers...

nsIFoo* fooPtr = 0;
// ...
fooPtr->SomeFunction(x, y, z);
AnotherFunction(fooPtr);

if ( fooPtr )
  // ...

if ( fooPtr == foo2Ptr )
  // ...
// |nsCOMPtr|...

nsCOMPtr<nsIFoo> fooPtr;
// ...
fooPtr->SomeFunction(x, y, z);
AnotherFunction(fooPtr);

if ( fooPtr )
  // ...

if ( fooPtr == foo2Ptr )
  // ...

There are two main differences. First: you no longer need, nor are you allowed, to call AddRef() or Release().
Comparison 3. Differences: AddRef() and Release() are illegal for nsCOMPtrs.
// raw [XP]COM interface pointers...
// given: |nsIFoo* mFooPtr;|







NS_IF_RELEASE(mFooPtr);

mFooPtr = aFooPtr;
NS_IF_ADDREF(mFooPtr);

// |nsCOMPtr|...
// given: |nsCOMPtr<nsIFoo> mFooPtr;|

  /*
    You no longer need, nor will the
    compiler let you, call |AddRef()|,
    or |Release()|.
  */

NS_IF_RELEASE(mFooPtr);
  // Error: |Release()| is private
mFooPtr = aFooPtr;
NS_IF_ADDREF(mFooPtr);
  // Error: |AddRef()| is private

Second: you can't just pass the address of an nsCOMPtr to a getter expecting to return a result through a raw [XP]COM interface pointer parameter. You have to `annotate' the nsCOMPtr with the getter_AddRefs() directive.
Comparison 4. Differences: apply getter_AddRefs() when using an nsCOMPtr as a `out parameter'.
// raw [XP]COM interface pointers...

nsIFoo* foo;

GetFoo(&foo);
// |nsCOMPtr|s...

nsCOMPtr<nsIFoo> foo;

GetFoo(getter_AddRefs(foo));

That's it. You now know enough to start using nsCOMPtrs. There are a few other details you will want to know as you use nsCOMPtr in more complicated situations, but what you've just learned will cover 90% of your uses. There are a couple of `accidental' differences, due to bugs in some of our compilers. These are things you want to avoid, so that you don't break somebody elses build. The unfortunate truth about these differences is that they probably compile on your platform. I wish they compiled everywhere, but they don't, so beware.
Comparison 5. Avoid these compiler traps.
// Things some of our compilers hate...

nsIFoo* rawFooPtr;
nsCOMPtr<nsIFoo> foo;

// ...

  // Don't start a comparison with |0|,
  //  or |NS_NULL|...
if ( NS_NULL != foo )
  // ...

  // Similarly, |==|.


  // Avoid comparing an |nsCOMPtr| to
  //  a raw [XP]COM interface pointer
if ( foo == rawFooPtr )
  // ...

  // Similarly, |!=|, or re-ordering
// ...so do it this way, instead.

nsIFoo* rawFooPtr;
nsCOMPtr<nsIFoo> foo;

// ...


  // ...prefer the implicit test
if ( foo )
  // ...

if ( !foo )
  // ...


  // ...prefer two raw pointers
if ( foo.get() == rawFooPtr )
  // ...


A Few Details

There are a couple more things that will help you get the most out of nsCOMPtr.

Very often, you first get an interface pointer by calling QueryInterface(). QueryInterface() is a getter like any other, and you already know one way to call it, applying the getter_AddRefs() rule, as described above.
The hard way to QueryInterface() into an nsCOMPtr.
// A way (though not the best way) to |QueryInterface()| into an |nsCOMPtr|...

nsCOMPtr<nsIFoo> foo;

nsresult rv = bar->QueryInterface(NS_GET_IID(nsIFoo), getter_AddRefs(foo));

  // Or, if you're a savvy [XP]COM programmer,
  //  you use the type-safe version...
nsresult rv = CallQueryInterface(bar, getter_AddRefs(foo));

QueryInterface() is used so frequently, though, that nsCOMPtr has a special facility to call it. This facility is type-safe, and it enables an nsCOMPtr to be directly constructed from the result of QueryInterface(). Construction from the correct value is more efficient that construction followed by assignment. This facility is the do_QueryInterface() directive. Using do_QueryInterface(), the sample above would look like this
How to QueryInterface() into an nsCOMPtr.
// The best way to |QueryInterface()| into an |nsCOMPtr|...

nsresult rv;
nsCOMPtr<nsIFoo> foo = do_QueryInterface(bar, &rv);

  // Or, if you don't care about the |nsresult|
nsCOMPtr<nsIFoo> foo = do_QueryInterface(bar);

nsCOMPtr happily calls AddRef() and Release() implicitly. This same favor is not extended to QueryInterface(). nsCOMPtr does not QueryInterface() on assignment without your explicit permission in the form of the do_QueryInterface() directive. You need never worry about hidden queries. However, be aware that if you should have queried but didn't, e.g., when assigning in a raw pointer where C++ allows the assignment, but [XP]COM wouldn't, nsCOMPtr will assert at runtime. Use do_QueryInterface() whenever you assign in a pointer to a [XP]COM interface of a different type, even if that type happens to derive from the base type of the nsCOMPtr
Comparison 6. do_QueryInterface() prevents [XP]COM type errors.
class nsIBar
  : public nsIFoo ... { ... };

nsIBar* p = ...;

  // C++ thinks every |nsIBar*| is an
  //  |nsIFoo*|, therefore, C++ allows
  //  this...
nsCOMPtr<nsIFoo> foo = p;
  //  ...even though it is an [XP]COM
  //  type error
class nsIBar
  : public nsIFoo ... { ... };

nsIBar* p = ...;



  // No type error here...
nsCOMPtr<nsIFoo> foo = do_QueryInterface(p);


Remember, the C++ type system and the [XP]COM type system are really two independent things. Because [XP]COM interfaces are expressed as abstract C++ base classes, you may be tempted to let C++ handle the differences, or to use C++ casts to navigate between interface types. This is wrong. The only sanctioned way to get between [XP]COM types is with QueryInterface(). In the example above, there is no reason to assume that the nsIFoo* C++ pulls out of p would be the same one that p->QueryInterface() would return.

dont_AddRef() is a similar directive that helps you when you assign in a pointer that has already been AddRef()ed, e.g., because you called a getter that returned the pointer as its function result.
Using dont_AddRef().
nsCOMPtr<nsIFoo> foo = dont_AddRef(CreateFoo());
  // |CreateFoo()| |AddRef()|s its result, as all good getters do

Something nsCOMPtr Doesn't Do

An nsCOMPtr does all that is necessary to behave as an owning reference. A given nsCOMPtr does not, however, cooperate in making other owning pointers. After learning how nsCOMPtr automatically AddRef()s a pointer as it is being assigned in, the natural assumption is that it does the same thing when assigning out. Here is a snippet of code that demonstrates this misconception.
// Incorrect assumptions about |nsCOMPtr|...

nsresult
nsCacheRecord::GetFileSpec( nsIFileSpec** aFileSpecResult )
    /*
      ...fills in the callers |nsFileSpec*| (which the caller supplied
      the address of) with a copy of my member variable |mFileSpec|,
      an |nsCOMPtr|.  I.e., this function is a `getter'.

      Remember: good [XP]COM getters always |AddRef()| their result.
    */
  {
    // ...
    *aFileSpec = mFileSpec;
      // the |nsCOMPtr| should take care of the refcount here, right?
    return NS_OK;
  }

Plainly, the author believed (though perhaps with some question) that the nsCOMPtr, mFileSpec, would AddRef() automatically as it was assigned into *aFileSpec. This is not the case. An nsCOMPtr automatically calls AddRef() and Release() (only) on its own behalf. In all other situations, it is designed to be a drop in replacement for a raw [XP]COM pointer. Where ever an nsCOMPtr is used in a situation where a raw pointer is needed, the nsCOMPtr automatically provides one.
// |nsCOMPtr| produces a raw pointer when needed...

nsCOMPtr<nsIFoo> foo = ...;

  // 1.  Assigning into a raw pointer
nsIFoo* raw_foo = foo;

  // 2.  Assigning into another |nsCOMPtr|
nsCOMPtr<nsIFoo> foo2 = foo;

  // 3.  As a parameter
SetFoo(foo);

  // 4.  Testing the value in an |if| expression
  // 5.  Calling a member function
if ( foo )
  foo->DoSomething();

In all of these cases, pretty much the exact same code is executed (case 2 is slightly different, but the intent is the same). In each case, you are essentially extracting the raw pointer value for your own purpose. If the nsCOMPtr AddRef()ed the value each time you did that, cases 4 and 5 would obviously always generate leaks. SetFoo(), from case 3, would have to be written two different ways when given an nsCOMPtr, it would know the value was already AddRef()ed, and when given a raw pointer it would assume the value was not AddRef()ed. Actually the contradictions run deeper than that. All these cases show that automatically AddRef()ing on `output' makes nsCOMPtrs and raw-pointers act differently from the point of view of the clients. The goal is to make them act the same so that nsCOMPtrs can be a drop in replacement (modulo managing its own `ownership').

Given what you now know, the rule is predictable. As described above, and unless you tell it otherwise, an nsCOMPtr AddRef()s when you assign in to it. It does nothing when you assign out of it.

Where should I use nsCOMPtrs?

You should use an nsCOMPtr any place you use an interface pointer as an owning reference, i.e., where you call AddRef() and Release() on it. You should use nsCOMPtr as a member variable, where it will simplify setters, and eliminate constructors, destructors, and assignment operators. You should use nsCOMPtr on the stack, where it makes calling QueryInterface() almost pleasant, and eliminates the complex logic that falls out of error handling.

Where shouldn't I use nsCOMPtrs?

Don't use nsCOMPtrs where you don't need an owning reference. See Some COM Ownership Guidelines[#]. Don't use an nsCOMPtr to point to something other than an [XP]COM interface. Don't use nsCOMPtrs in [XP]COM interfaces, or in such a way that your use forces them on others. Don't use them in plain old C code; nsCOMPtrs are, of course, a C++ only construct.

Summary

An nsCOMPtr is an owning reference. Whatever it points to has been AddRef()ed, counting the nsCOMPtr as one of its `owners'. An nsCOMPtr always calls Release() before letting go, whether the nsCOMPtr is letting go so that it can point to a different object, or because the nsCOMPtr is going out of scope. Any time a new value is assigned into an nsCOMPtr, the nsCOMPtr automatically always Release()s its old referent, if any, and (unless you tell it you already have) AddRef()s the new.

You use an nsCOMPtr exactly as you would a raw [XP]COM interface pointer in almost all cases [though note the compiler problems shown in Comparison 5]. You won't have to explictly call AddRef() or Release() through it, nor will the compiler allow it. The only place you can't use an nsCOMPtr without change is where a raw [XP]COM interface pointer is an `out' parameter. In this case, you wrap the nsCOMPtr with getter_AddRefs() [see Comparison 4].

When assigning into an nsCOMPtr, you will usually just supply another pointer (either a raw [XP]COM interface pointer or an nsCOMPtr), with no additional directives [see, e.g., the nsCOMPtr side of Comparison 1]. As stated above, with no directives, the nsCOMPtr will Release() its old referent, if any, and AddRef() the new. This is appropriate when the thing you're assigning in hasn't yet been AddRef()ed to account for the new reference. This is typically the case when you are assigning in a pointer that you didn't call a function to get, e.g., one that was passed in as a parameter, or that you pulled out of a structure.

You can tell nsCOMPtr it doesn't need to AddRef() the new value on assignment by wrapping the new value in dont_AddRef(). Do this, for example, when you got the new value from a function which, like all good [XP]COM getters, already called AddRef() on your behalf.

You may not assign in a pointer to a different interface type; you must first query it to the right type [see, e.g., Comparison 6. and the surrounding discussion]. nsCOMPtr never calls QueryInterface() implicitly, i.e., you must call it yourself, or explictly ask nsCOMPtr to call it with do_QueryInterface(). The do_QueryInterface() directive allows you to do the query as part of the assignment. This better facilitates constructing an nsCOMPtr directly from the right value, rather than constructing it and assigning in the correct value later. Construction alone is more efficient than construction followed by assignment. Prefer construction over assignment whereever reasonable. Be careful not to apply do_QueryInterface() to a function returning an AddRef()ed pointer [see this short section for an explanation]

For more details, continue on to the Reference Manual.


Reference Manual

This section will help you if you're already familiar with nsCOMPtr but you need details. If you've never use nsCOMPtrs before, you might want to read the Getting Started Guide first. If you're trying to fix a broken build, the FAQ might lead you to the answer more quickly.

The Basics

Design

An nsCOMPtr is designed to be a complete replacement for raw [XP]COM interface pointers where they are used as owning references. Almost any place you could use a raw [XP]COM interface pointer, you should be able to use an nsCOMPtr. An nsCOMPtr is the exact same size and shape as a raw [XP]COM interface pointer. It can be used as a member variable without introducing bloat.

Most of the work of being an owning reference can be done in the constructor, destructor, and assignment operators of nsCOMPtr. Whenever you `point' the nsCOMPtr at a different [XP]COM object (by assignment or initialization), it must Release() its old value, if any, and AddRef() the new. At its own destructor time it must Release() as well. nsCOMPtr only does exactly the work you would have done, if you always remembered to do the right thing.

Safety Features

Type Safeguards

It is an invariant of nsCOMPtr that it holds the [XP]COM-correct interface pointer for it's underlying type. E.g., an nsCOMPtr<nsIFoo> will always hold the pointer that would be returned by QueryInterface(), when querying an [XP]COM object for its nsIFoo interface. In debug builds, if you subvert this invariant with one of the assignment forms that doesn't call QueryInterface(), nsCOMPtr will assert at runtime in the bad assignment.
// Given two un-related interfaces |nsIFoo| and |nsIBar|...
nsIBar* bar = ...;
// ...

nsCOMPtr<nsIFoo> foo = bar;
  // NS_ASSERTION: "QueryInterface needed"

  // ...even assuming you can get the line to compile
  //  (either by casting, or because the types are related by C++)

This invariant is relaxed for nsCOMPtr<nsISupports>. Like nsISupports* (or even void*), people generally use nsCOMPtr<nsISupports> to mean `any [XP]COM interface'. It would be annoying if nsCOMPtr forced you to QueryInterface() to the [XP]COM-correct nsISupports within an object in places where you don't care to know the exact type.

NULL-dereference Safeguards

An nsCOMPtr will also assert at runtime if you try to dereference it when it is void, e.g.,
nsCOMPtr<nsIFoo> foo;
  // Note: default initialized to |0|

foo->DoSomething();
  // NS_PRECONDITION: "You can't dereference a NULL nsCOMPtr with operator->()"

A similar precondition intervenes on behalf of operator*().

Reference-Counting Safeguards

All of the operations that extract the underlying raw pointer out of an nsCOMPtr use a C++ trick to implement another safety feature. The pointer returned cannot be AddRef()ed, Release()d, or deleted.
nsCOMPtr<nsIFoo> foo = ...;

foo->AddRef();     // Error: |AddRef()| is private
delete foo.get();  // Error: |operator delete()| is private
NS_RELEASE(foo);   // Error: |Release()| is private

Of course, the most important safety feature provided by nsCOMPtr is that it AddRef()s and Release()s automatically at the appropriate times.

Casting

Never use old-style C/C++ casts on an nsCOMPtr. An old-style cast is guaranteed to compile, even if it can't do the right thing. Old-style casts degenerate into the equivalent of reinterpret_cast if no conversion is defined. Such a cast can easily by-pass nsCOMPtrs machinery, causing leaks, type mismatches, and other calamities.
// Old-style C/C++ casts by-pass |nsCOMPtr|s machinery and cause leaks...

nsresult rv;
nsCOMPtr<nsIFoo> foo = ...;

// ...
rv = GetFoo( &(nsIFoo*)foo );
rv = GetFoo( (nsIFoo**)&foo );
  // Sure, they compile; but now you leak.

Implementation Details and Debugging Machinery

Although it is a class, nsCOMPtr has no virtual methods, and therefore, no vtable or vptr. Because a few key routines are factored out into a common non-template base class, the actual underlying pointer is stored as an nsISupports* (except in debug builds where NSCAP_FEATURE_DEBUG_PTR_TYPES is turned on). It is because of these factored routines that nsCOMPtr users must link with the XPCOM library.

When NSCAP_FEATURE_DEBUG_PTR_TYPES is turned on, instead of holding its underlying pointer in a variable of type nsISupports*, the nsCOMPtr holds it in a pointer matching the underlying type. This allows source level debuggers to more easily `follow' the pointer. However, the routines that would normally be factored into a base class now must become template-specific inlines. There is no factored base class. This implies that the entire application must be compiled with the same setting of NSCAP_FEATURE_DEBUG_PTR_TYPES, else some parts will be expecting a base class and others will not. The app will not link.

Unit Tests

The unit tests for nsCOMPtr can be found in the file

Initialization and Assignment

Built-in forms

Assignment into, or initialization of an nsCOMPtr is easy to understand. The nsCOMPtr Release()s its old value, if any, and then assigns in the new value, AddRef()ing it and/or calling QueryInterface() as you direct by `annotating' the assignment with directives like dont_AddRef. This section describes each of the possibilities, though the directives can be more succinctly described in the table below.

You can construct an nsCOMPtr from, or assign into it any of the following

The first three of these are simple and obvious. The fourth (applying the dont_QueryInterface() directive) is a synonym for just assigning in a raw [XP]COM interface pointer of the same type. The remaining directives provide some additional control in special situations. Additionally, you can construct an nsCOMPtr without supplying an initial value, in which case it is initialized to 0. Just like a primitive pointer, an nsCOMPtr with the value 0 points to no object, and can be tested with expressions like if (foo) and if (!foo).

The directives mentioned above may make more sense in this table

Table 1. Options for assigning into an nsCOMPtr.
don't QI QI
AddRef() T*,
dont_QueryInterface(T*)
do_QueryInterface(nsISupports*),
do_QueryInterface(nsISupports*, nsresult*)
do_QueryReferent(nsIWeakReference*),
do_QueryReferent(nsIWeakReference*, nsresult*)
don't AddRef() dont_AddRef(T*),
getter_AddRefs(T*)
n/a

E.g., one of the possibilities for assigning into an nsCOMPtr, but you don't want to AddRef() the pointer you are assigning (because it has already been AddRef()ed for some reason) is dont_AddRef(T*) found at the intersection of "don't AddRef()" and "don't QI". Here is a sample demonstrating the various positions these `annotations' can appear in, using dont_AddRef
// Controlling assignment into an |nsCOMPtr|...

  // in constructors...
nsCOMPtr<nsIFoo> foo1 = dont_AddRef(rawFoo1Ptr);
nsCOMPtr<nsIFoo> foo2( dont_AddRef(rawFoo2Ptr) )
  // Note that the assignment form and the function form of a constructor have
  //  identical meaning

nsCOMPtr<nsIFoo> foo3;

  // in a normal assignment...
foo3 = dont_AddRef(rawFoo3Ptr);

  // The annotations described in the table apply to both forms of constructor,
  //  and to plain-old assignment

Any of the annotations shown in the table can appear in all the positions demonstrated with dont_AddRef. The sections that follow describe each possibility.

nsCOMPtr<T> = T*,
nsCOMPtr<T> = dont_QueryInterface( T* )

The default behavior, shown in the table as T*, is to AddRef() the new value, but not to call QueryInterface() against it. This is what happens when no `annotation' is present, e.g.,
nsCOMPtr<nsIFoo> foo = aFooPtr;
  // ...will call |AddRef()| but not |QueryInterface()|

  // A more explicit synonym for this is...
nsCOMPtr<nsIFoo> foo = dont_QueryInterface(aFooPtr);

By using this form, you are promising that the pointer you are assigning in is already a pointer to the [XP]COM-correct interface matching the nsCOMPtrs underlying type, in this case, nsIFoo.

nsCOMPtr<T> = do_QueryInterface( nsISupports* ),
nsCOMPtr<T> = do_QueryInterface( nsISupports*, nsresult* )

If you can't satisfy the above promise, you can `annotate' the assignment to tell the nsCOMPtr it needs to call QueryInterface(), e.g.,
nsCOMPtr<nsIFoo> foo = do_QueryInterface(aBarPtr);
  // ..._will_ call |QueryInterface()| (and therefore, |AddRef()|)

  // Of course, since you're calling |QueryInterface()|, you might need the
  //  error result...
nsresult rv;
nsCOMPtr<nsIFoo> foo = do_QueryInterface(aBarPtr, &rv);

nsCOMPtr<T> = dont_AddRef( T* ),
nsCOMPtr<T> = getter_AddRefs( T* )

Sometimes, you happen to have a pointer lying around that's already AddRef()ed, but you want to put it into an nsCOMPtr. This often happens with getters that return the AddRef()ed pointer as their result (rather than an nsresult); or in the efficiency transformations. dont_AddRef is the perfect remedy to situations like this.
nsIFoo* temp;
nsresult rv = GetFoo(&temp);
nsCOMPtr<nsIFoo> foo = dont_AddRef(temp);
  // |temp| has already been |AddRef()|ed, but we want to manage it with an
  //  |nsCOMPtr|.

nsCOMPtr<nsIFoo> foo = getter_AddRefs(CreateAFoo());
  // |getter_AddRefs| is a synonym for |dont_AddRef| that may look better to
  //  you when applied to functions that return |AddRef()|ed pointers

nsCOMPtr<nsIFoo> foo = dont_AddRef(CreateAFoo());
  // or, maybe you don't like it better...

nsCOMPtr<T> = /* call QueryInterface() but don't AddRef() */

You'll notice this quadrant of the table is marked `n/a'. There is no explicit directive that means "call QueryInterface(), but don't AddRef() the result". This option corresponds to the situation where you are calling a getter that returns an object of the wrong type. It has already AddRef()ed the object, so you don't want to, but you need to get a different interface out of it. Well, you can't have it. QueryInterface() always AddRef()s it's result, and there is no substitute for calling QueryInterface() to get the right type. The solution is a two step process.
// ...

  // The getter returns an already |AddRef()|ed object (of the wrong type)...
nsCOMPtr<nsIBar> bar = getter_AddRefs(CreateBar());
  // ...which I must query for the right type
nsCOMPtr<nsIFoo> foo = do_QueryInterface(bar);

One unfortunate trap that people fall into in this case is forgetting that their getter function AddRef()ed the result. Which leads them to type in code that looks like this:
nsCOMPtr<nsIFoo> foo = do_QueryInterface(CreateBar());
  // Oops!  The interface returned by |CreateBar()| leaks.
  //  You _must_ handle this case with the two step solution shown above.

  // Seems unlikely, you say?  You're more likely to see it in a form like this
nsCOMPtr<nsIFoo> foo = do_QueryInterface(aList->ElementAt(i));
  // |ElementAt()|, like all good getters, |AddRefs()| it's result
  //  which would be dropped on the floor, after querying it for the needed
  //  interface

Bugzilla bug# 8221 is specifically about finding and fixing this particular kind of leak.

nsCOMPtr helpers

nsCOMPtr<T> = do_QueryReferent( nsIWeakReference* ),
nsCOMPtr<T> = do_QueryReferent( nsIWeakReference*, nsresult* )

do_QueryReferent() exists to facilitate weak references based on nsIWeakReference. An nsIWeakReference is an [XP]COM object that acts as a proxy for another object. The nsIWeakReference and this other object have a special relationship. They know about each other, but neither holds an owning reference to the other. The two objects cooperate to ensure that neither ever holds a dangling pointer to the other. Holding an owning reference on the nsIWeakReference object allows you to get to this other object when you need to, but does not require it to go on living, just for you. To get to the object, you ask the nsIWeakReference object to QueryInterface() it on your behalf. If the object still exists and supports the requested interface, you will (hopefully, temporarily) hold an owning reference to it.
nsIWeakReference* weakPtr = ...;

weakPtr->QueryReferent(

Using an nsCOMPtr<T> as a T*

Using an nsCOMPtr as a pointer

`In' Parameters

`Out' Parameters: getter_AddRefs()

Assignment into an nsCOMPtr is fairly easy to understand. The nsCOMPtr Release()s its old value, if any, and then assigns in the new value, AddRef()ing, and/or calling QueryInterface() as you specified with the directives described above. These rules apply equally to the `assignment' that happens when copying parameters or function results that are declared to be nsCOMPtrs. If we want nsCOMPtrs to be a viable substitute for raw [XP]COM interface pointers, however, we will need to deal with the issue of `out' parameters. Many [XP]COM functions return interface pointers as results through parameters, e.g.,
// Getters can return interface pointers through `out' parameters...

nsresult GetFoo( nsIFoo** );     // a standard getter
nsresult GetFoo2( nsIFoo*& );    // a non-standard getter
nsresult GetSomething( void** ); // an `un-typed' getter
  // Note: |QueryInterface()| is an example of a `un-typed' getter

We must be able to pass nsCOMPtrs by pointer or reference, into routines for use as `out' parameters. The problem is, that inside the getter there is no knowledge of nsCOMPtrs. It thinks it's getting a pointer (or a reference) to a raw [XP]COM interface pointer. nsCOMPtrs smart assignment operators will not be called. The old value, if any, will be leaked.

This is where the getter_AddRefs( nsCOMPtr& ) comes in. getter_AddRefs Release()s the old value, if any, clears it out, and returns a pointer to it, allowing the getter to fill in your nsCOMPtr with a new AddRef()ed value. We use getter_AddRefs() as a sort of replacement for the & that we would apply to a raw [XP]COM interface pointer in these situations. getter_AddRefs() packages up all the magic we normally get from nsCOMPtrs constructors and assignment operators.
// raw [XP]COM interface pointers...

nsIFoo* foo;

GetFoo(&foo);
GetFoo2(foo);
GetSomething((void**)&foo);
// |nsCOMPtr|s...

nsCOMPtr<nsIFoo> foo;

GetFoo(getter_AddRefs(foo));
GetFoo2(*getter_AddRefs(foo));
GetSomething(getter_AddRefs(foo));

Why not just overload operator&() to do this work? Several reasons: it would become inconvenient take the address of an nsCOMPtr in all other situations; the name `getter_AddRefs' enforces the notion that a certain behavior is required of the getter; and once upon a time, there was another possibility (as you're about to learn).

Is there a getter_doesnt_AddRef( nsCOMPtr& ) for getters that return non-AddRef()ed results through a parameter? No, there isn't. Once upon a time, there was, but it went away for three reasons:

// Calling a getter that (illegally) doesn't |AddRef()| its result...

nsIFoo* temp;
nsresult rv = GetFoo_WithoutAddRef(&temp);
  // Note to self: must report |GetFoo_WithoutAddRef()| as a bug, all getters
  //  must |AddRef()|
nsCOMPtr<nsIFoo> foo = temp;

`In/Out' Parameters

What about `in/out' parameters?

Efficiency and Correctness

The Costs of nsCOMPtr

nsCOMPtr is tuned to be a viable replacement for raw [XP]COM interface pointers, anywhere you would use one as an owning reference. nsCOMPtrs performance is generally slightly more efficient that raw pointers in space, and negligably less efficient in time. Performance concerns should not deter you from using nsCOMPtr. The patterns presented throughout this section will help you get the most out of nsCOMPtr.

Space

In general, nsCOMPtr can be more efficient in space than using raw [XP]COM pointers. This is primarily because it factors its destructor, and the more complicated constructors and assignment operators. By following the optimization tips in this section, you will write code that generates fewer bytes of object than you might with raw pointers. Even if you don't follow these suggestions, your nsCOMPtr code may still end up smaller, or at worst only negligable bulkier than the raw pointer version. See Code Bloat [LONG, summary at top] for details, though the recommendations from that document are re-iterated here.

Time

[[More time-performance measurements are needed.]]

In places where two or more subroutines calls are required, i.e., of AddRef(), Release(), and QueryInterface(), some nsCOMPtr routines are factored, and hence, require additional time corresponding to invoking a subroutine. This time is negligable, especially in the face of work done by QueryInterface(), and the work that may be done by Release().

In all other cases, nsCOMPtr does only the work you would have done by hand. The bulk of the work for which an nsCOMPtr is used is dereferencing with operator->(), just as it is with a primitive pointer. On every platform, this operation generates the exact same code, and takes the same time, as performing this operation on a raw [XP]COM interface pointer. The destructor, which corresponds to client code calling Release() against a raw [XP]COM interface pointer, is factored, requiring the extra time required to invoke a subroutine call, though this is balanced against the cost already present in both cases of calling Release() which may, in turn, invoke delete and the referents destructor. All nsCOMPtrs constructors and assignment operators are inline. The simple constructors, i.e., those that don't query, do only exactly the same work that you would do by hand. Any routines that call more than one of AddRef(), Release(), or QueryInterface(), are factored, and hence have the additional cost of invoking a subroutine call.

Only the fact that some routines are factored, thus introducing the overhead of an additional subroutine call, and that initialization cannot be by-passed, cause any extra run-time cost for nsCOMPtr over raw [XP]COM interface pointers. Space and time trade-offs are finely balanced in nsCOMPtr. The factored routines are the direct result of bloat measurements.

Prefer Construction to Assignment

The most efficient way, in both time and space, to get a value into an nsCOMPtr is at construction time. Prefer construction over assignment whenever reasonable. Initialize member nsCOMPtrs in the member initialization clause of your constructor.
// Initialize member |nsCOMPtr|s in the member initialization clause of your
//  constructor...

class Bar
  {
    public:
      Bar( nsIFoo* initial_fooPtr );
      // ...
    private:
      nsCOMPtr<nsIFoo> mFooPtr;
  };

Bar::Bar( nsIFoo* initial_fooPtr )
    : mFooPtr(initial_fooPtr) // initialize it _here_
  {
    // not here
  }

Additionally, there is an optimization pattern using a temporary that converts assignment form to construction form.
// Default construction, followed by
//  assignment is not as efficient...

nsCOMPtr<nsIFoo> foo;
nsresult rv=GetFoo(getter_AddRefs(foo));





// ...as construction alone.

nsIFoo* temp;
nsresult rv=GetFoo(&temp);
nsCOMPtr<nsIFoo> foo=dont_AddRef(temp);

  // Remember this `raw-pointer, call
  //  getter, assign |dont_AddRef|'
  //  pattern.  It  crops up in many
  //  efficiency discussions.

In both cases you end up with foo, a valid nsCOMPtr whose value was set with the product of GetFoo, and rv the status returned by GetFoo. The case using the temporary, however, uses construction to put the value into the nsCOMPtr, which (though slightly more complicated in source) is more efficient than default construction followed by assignment, the course of events followed by the simpler example.

Prefer Destruction to Assignment

Prefer do_QueryInterface() to calling QueryInterface()

Iterating

There is a very common idiom for iterating over data-structures with normal pointers, e.g.,
// Iterating with pointers to non-[XP]COM objects...

Node* p = ...;
while ( p )
  {
    // ...
    p = p->next;
  }

One often sees this pattern expressed as a for loop, as well. Consider, however, what would happen if you were trying to do this with a raw [XP]COM interface pointer.
// Iterating with raw [XP]COM interface pointers...

nsIDOMNode* p = ...;
while ( p )
  {
    // ...
    p->GetNext(&p);
      // Trouble!  We overwrote |p| without |Release()|ing it.
  }

Oops! We just failed to Release() p before putting a new pointer into it. People do this a lot, and it turns out to be a big source of leaks in normal [XP]COM code. Well, could we do this instead?
// Iterating with raw [XP]COM interface pointers...

nsIDOMNode* p = ...;
while ( p )
  {
    // ...
    NS_RELEASE(p);
    p->GetNext(&p);
      // Trouble!  We tried to call a member function of a pointer
      //  that may be dangling or |NULL|.
  }

Unfortunately, not. After the Release(), p could be dangling. In fact, if you used the NS_RELEASE macro, p would be NULL by the time you got to the GetNext call.

Now imagine that you've written the same thing with nsCOMPtr.
// Iterating with |nsCOMPtr|s...

nsCOMPtr<nsIDOMNode> p = ...;
while ( p )
  {
    // ...
    p->GetNext( getter_AddRefs(p) );
      // Trouble!  We tried to call a member function through a |NULL| pointer.
  }

Using nsCOMPtr is exactly like using raw [XP]COM interface pointers, here. getter_AddRefs Release()s and clears out p before you assign into it, i.e., before GetNext is called. Which means that by the time we get around to calling GetNext, we are trying to call it through a NULL pointer. Unlike raw [XP]COM interface pointers, nsCOMPtr will fire an assert() instead of blindly trying to call GetNext through a NULL pointer.

That's the problem. So what's the solution? If this were raw [XP]COM interface pointers, we'd probably introduce a temporary. We can do the same thing with nsCOMPtr.
// Safe iterating with raw [XP]COM
//  interface pointers...

nsIDOMNode* p = ...;
while ( p )
  {
    // ...

      // Introduce a temporary so we
      //  don't stomp on |p|
    nsIDOMNode* temp = p;
    temp->GetNext(&p);
    NS_RELEASE(temp);
  }
// Safe iterating with |nsCOMPtr|...


nsCOMPtr<nsIDOMNode> p = ...;
while ( p )
  {
    // ...

      // Introduce a temporary so we
      //  don't stomp on |p|
    nsCOMPtr<nsIDOMNode> temp = p;
    temp->GetNext(getter_AddRefs(p));
  }

Although the nsCOMPtr parallel is easy to understand, it suffers from doing one extra AddRef() and one extra Release() compared to the raw pointer scheme. A slight transformation makes the code uglier, but (possibly negligably) more efficient.
// Safe, efficient, iterating with |nsCOMPtr|...

nsCOMPtr<nsIDOMNode> p = ...;
while ( p )
  {
    // ...
    nsIDOMNode* next;
    p->GetNext(&next);
    p = dont_AddRef(next);
  }

  // Look!  It's our friend, the `raw pointer, call getter, assign
  //  |dont_AddRef|' pattern.

Writing Getters

Compiler Annoyances


Frequently Asked Questions

This section will help you if you're fixing a broken build, or have what you think is a quick obvious question, and you don't have time to read the Reference Manual. This FAQ usually just refers back directly to the appropriate answer, there. If you're looking here just to learn about nsCOMPtrs, you'll get a better introduction in the Getting Started Guide.

The FAQ is divided into sections to help you find what you're looking for faster. In most cases, the answer will just refer back into the reference manual, above. No need to explain things twice :-).

Buildtime Errors

The build just broke. It's not in your code, or it's not on your platform, but there's an nsCOMPtr on the line where the error is and you're suspicious. You're looking in the right place.

comparing an nsCOMPtr to a raw [XP]COM interface pointer

declaring an nsCOMPtr to a forward-declared class

not linking to XPCOM

not including nsCOMPtr.h

different settings of NSCAP_FEATURE_DEBUG_PTR_TYPES

Runtime Errors

NS_ASSERTION "QueryInterface needed"

NS_PRECONDITION "You can't dereference a NULL nsCOMPtr with operator->()"

NS_PRECONDITION "You can't dereference a NULL nsCOMPtr with operator*()"

How do I...

initialize an nsCOMPtr?

Release() an nsCOMPtr before it goes out of scope?

Assign 0 into it. Whenever an nsCOMPtr takes on a new value, it always Release()s its old value, if any. Assigning in the value 0 is just like assigning in a raw pointer that happens to be NULL. The old referent will be Release()d. [See Initialization and Assignment for more details]

You should note, though, that there is a small performance penalty for this. The nsCOMPtr will still exercize logic in its destructor to attempt to Release() the value it has at that time. The optimal solution is to arrange the lifetime of your nsCOMPtr to correspond to exactly how long you want to hold the reference. E.g., using blocks as in this sample
// The most efficient scheme is to scope your |nsCOMPtr| to live exactly as long
//  as you need to hold the reference

nsresult
SomeLongFunction( nsIBar* aBar )
  {
    nsresult rv;
    // ...

    {
      // I only need the |nsIFoo| interface for a short time
      //  so I control its lifetime by declaring it inside
      //  a block statement.

      nsCOMPtr<nsIFoo> foo = do_QueryInterface(aBar, &rv);
      if ( foo )
        foo->DoSomeFooThing();

      // |foo| goes out of scope, and so |Release()|s its referent, here
    }

    // ...tons of stuff here, during which I don't need an |nsIFoo|

    return rv;
  }

[[Move this discussion to the efficiency section, and link to it from here.]]

make an nsCOMPtr leak (for a debug test)?

call a getter that uses a raw [XP]COM interface pointer as an `in/out' parameter?

call a getter that fills in an nsIFoo*& parameter?

call a getter that doesn't AddRef() its result?

Any [XP]COM function that returns an interface pointer, i.e., a `getter', must have already AddRef()ed that pointer. If it didn't, you should probably report it as a bug. No matter which code pattern you use to solve this problem, you should comment it, e.g., // Warning: this getter doesn't AddRef() its result. If the getter returns the new pointer as its function result, no worries,
  

General

Does nsCOMPtr bloat the code?

Are nsCOMPtrs fast? Can I use them in tight loops?


Bibliography

Web Resources

nsCOMPtr.h, and nsCOMPtr.cpp are the source to nsCOMPtr. You can examine the source to nsCOMPtr online using (the wonderful) LXR. Exploring this code is not an adventure for the faint of heart.

Some COM Ownership Guidelines.

Interface Pointers Considered Harmful by Don Box originally appeared in the September 1995 issue of "The C++ Report".

COM Smart Pointers Even More Harmful by Don Box is a follow-up article that originally appeared in the February 1996 issue of "The C++ Report".

Books

Essential COM by Don Box.

Effective COM by Don Box, et al.

The C++ Programming Language (3rd Edition) by Bjarne Stroustrup.

Effective C++ (2nd Edition): 50 Specific Ways to Improve Your Programs and Designs by Scott Meyers.

More Effective C++: 35 New Ways to Improve Your Programs and Designs by Scott Meyers.

Effective C++ CD: 85 Specific Ways to Improve Your Programs and Designs by Scott Meyers.

People

Don Box is a smart guy who has been writing about COM programming for a long time.


Copyright© 1999 by the Mozilla organization; use is subject to the NPL.