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.
nsCOMPtr is designed to be a complete replacement for raw XPCOM interface pointers where they are used as owning references. Almost any place you could use a raw XPCOM interface pointer, you should be able to use an
nsCOMPtr is the exact same size and shape as a raw XPCOM 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 XPCOM 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.
It is an invariant of
nsCOMPtr that it holds the XPCOM-correct interface pointer for it's underlying type. For example, an
nsCOMPtr<nsIFoo> will always hold the pointer that would be returned by
QueryInterface, when querying an XPCOM object for its
nsIFoo interface. In debug builds, if you subvert this invariant with one of the assignment forms that doesn't call
nsCOMPtr will assert at runtime in the bad assignment.
This invariant is relaxed for
nsISupports* (or even
void*), people generally use
nsCOMPtr<nsISupports> to mean "any XPCOM interface." It would be annoying if
nsCOMPtr forced you to
QueryInterface to the XPCOM-correct
nsISupports within an object in places where you don't care to know the exact type.
nsCOMPtr will also assert at runtime if you try to dereference it when it is void, e.g.,
A similar precondition intervenes on behalf of
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
Of course, the most important safety feature provided by
nsCOMPtr is that it
Releases automatically at the appropriate times.
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.
To help prevent this, we are trying to make the first form, above, illegal by making
private. See bug 59414.
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.
NSCAP_FEATURE_DEBUG_PTR_TYPES is turned on, instead of holding its underlying pointer in a variable of type
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.
The unit tests for
nsCOMPtr can be found in the file
Assignment into, or initialization of an
nsCOMPtr is easy to understand. The
Releases its old value, if any, and then assigns in the new value,
AddRefing 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 value
nsCOMPtrof the same type
- a raw XPCOM interface pointer of the same type
- a raw XPCOM interface pointer of the same type, annotated with the
- a raw XPCOM interface pointer of the same type, annotated with the
dont_AddRefdirective or a synonym
- any interface pointer (either
nsCOMPtror a raw XPCOM interface pointer) of any type, annotated with the
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 XPCOM 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
The directives mentioned above may make more sense in this table
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
AddRefed 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
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.,
By using this form, you are promising that the pointer you are assigning in is already a pointer to the XPCOM-correct interface matching the
nsCOMPtrs underlying type, in this case,
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
nsCOMPtr<T> = dont_AddRef( T* ),
nsCOMPtr<T> = getter_AddRefs( T* )
Sometimes, you happen to have a pointer lying around that's already
AddRefed, but you want to put it into an
nsCOMPtr. This often happens with getters that return the
AddRefed pointer as their result (rather than an
nsresult); or in the efficiency transformations.
dont_AddRef is the perfect remedy to situations like this.
nsCOMPtr<T> = /* call
QueryInterface but don't
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
AddRefed 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.
AddRefs it's result, and there is no substitute for calling
QueryInterface to get the right type. The solution is a two step process.
One unfortunate trap that people fall into in this case is forgetting that their getter function
AddRefed the result. Which leads them to type in code that looks like this:
Bugzilla bug 8221 is specifically about finding and fixing this particular kind of leak.
nsCOMPtr<T> = do_QueryReferent( nsIWeakReference* ),
nsCOMPtr<T> = do_QueryReferent( nsIWeakReference*, nsresult* )
do_QueryReferent exists to facilitate weak references based on
nsIWeakReference is an XPCOM 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.
Assignment into an
nsCOMPtr is fairly easy to understand. The
Releases its old value, if any, and then assigns in the new value,
AddRefing, 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 XPCOM interface pointers, however, we will need to deal with the issue of "out" parameters. Many XPCOM functions return interface pointers as results through parameters, e.g.,
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 XPCOM 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.
Releases 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
AddRefed value. We use
getter_AddRefs as a sort of replacement for the
& that we would apply to a raw XPCOM interface pointer in these situations.
getter_AddRefs packages up all the magic we normally get from
nsCOMPtrs constructors and assignment operators.
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-
AddRefed results through a parameter? No, there isn't. Once upon a time, there was, but it went away for three reasons:
- It is against the rules of XPCOM for a getter to return a non-
AddRefed interface pointer through a parameter (if you see it, report a bug).
getter_doesnt_AddRefhad complex ramifications that ended up making
nsCOMPtrs either bigger or slower than raw XPCOM interface pointers.
- You can still call such a getter and put the result into an
nsCOMPtrwith a temporary, e.g.,
What about "in/out" parameters?
nsCOMPtr is tuned to be a viable replacement for raw XPCOM 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 can be more efficient in space than using raw XPCOM 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 negligibly 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.
[[More time-performance measurements are needed.]]
In places where two or more subroutines calls are required, i.e., of
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
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 XPCOM interface pointer. The destructor, which corresponds to client code calling
Release against a raw XPCOM 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
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 XPCOM interface pointers. Space and time trade-offs are finely balanced in
nsCOMPtr. The factored routines are the direct result of bloat measurements.
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.
Additionally, there is an optimization pattern using a temporary that converts assignment form to construction form.
In both cases you end up with
foo, a valid
nsCOMPtr whose value was set with the product of
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.
There is a very common idiom for iterating over data-structures with normal pointers, e.g.,
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 XPCOM interface pointer.
Oops! We just failed to
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 XPCOM code. Well, could we do this instead?
Unfortunately, not. After the
p could be dangling. In fact, if you used the
p would be
NULL by the time you got to the
Now imagine that you've written the same thing with
nsCOMPtr is exactly like using raw XPCOM interface pointers, here.
Releases 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 XPCOM interface pointers,
nsCOMPtr will fire an
assert instead of blindly trying to call
GetNext through a
That's the problem. So what's the solution? If this were raw XPCOM interface pointers, we'd probably introduce a temporary. We can do the same thing with
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 negligibly) more efficient.