Gecko code uses both nsCOMPtr
and RefPtr
as smart pointers. This guide provides some explanation and advice on how to choose between them.
nsCOMPtr
versus RefPtr
The general rule of thumb is to use nsCOMPtr<T>
when T
is an interface type, and RefPtr<T>
when T
is a concrete type.
This basic rule derives from the fact that some of the nsCOMPtr<T>
code is factored into the nsCOMPtr_base
base class, which stores the underlying mRawPtr
as an nsISupports*
. (although, confusingly, debug builds don't work this way). This design saves some space in the binary (or at least it used to). Since nsCOMPtr
stores the pointer as an nsISupports*
, it must be possible to unambiguously cast from T*
to nsISupports*
. Many concrete classes inherit from nsISupports
in more than one way, so they cannot be unambiguously cast to nsISupports*
. Thus, these concrete classes cannot be used with nsCOMPtr
.
While is possible to use nsCOMPtr<T>
on concrete classes T
that only singly inherit from nsISupports
, it is best to avoid doing so. In the future, more base classes might be added to T
that would then cause unrelated code to break, which would be very confusing. Hence, the interface versus concrete class rule of thumb: interfaces will never multiply inherit from nsISupports
, so they can always use be used with nsCOMPtr
without fear of breaking in the future. Concrete classes should only be used with RefPtr
.
nsCOMPtr<T>
also requires that you can QueryInterface
to type T
. It does this so that it can assert that mRawPtr
is a canonical T
pointer (i.e., that mRawPtr->QueryInterface(T_IID) == mRawPtr
).
do_QueryInterface
versus do_QueryObject
The do_QueryInterface
helper is only available when assigning to nsCOMPtr
. It also requires that the argument singly inherit from nsISupports
(since the type of the argument is nsISupports*
). For other cases, there is do_QueryObject
, which is essentially a more powerful form of do_QueryInterface
. It differs from do_QueryInterface
as follows:
do_QueryObject
inherits from nsCOMPtr_helper
, so it can be assigned into both nsCOMPtr
and RefPtr
. The downside of this inheritance is that do_QueryObject
requires an extra virtual call to operator()
in the helper method.do_QueryObject
is templated on the argument type, so it's possible to pass in objects that multiply inherit from nsISupports
. However, when the destination type is an XPCOM interface, it's probably better to static_cast
to a class that unambiguously inherits from nsISupports
and use do_QueryInterface
in such cases.