Gecko code uses both nsCOMPtr and RefPtr as smart pointers. This guide provides some explanation and advice on how to choose between them.

General Rule of Thumb for 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: