nsCOMPtr
nsCOMPtr是一个帮助防止泄漏的工具。
nsCOMPtr是一个智能指针,使用方法与C或者C++的普通指针一样,例如可以使用->或*。与原始的c++指针不同的是。nsCOMPtr帮助你管理着XPCOM的AddRef, Release和QueryInterface。
COM的一条原则是任何创建或者返回接口的函数都应该是已调用AddRef函数。
当最后一个指向接口的指针释放(调用Release),接口就将会删除自己(delete self)。如果有显示的调用接口的AddRef,而没有调用Release,则这个对象将引起内存泄漏(对象所占用的内存将不会被收回)。
拥有引用(owning reference)是通过显示调用AddRef 和Release的引用。
如果两个对象运行结束时,但相互拥有对方,这将引起两个对象回收失败。所以须要一种额外的机制,以破坏这种拥有环(ownership cycle)。
在以下几种情况下,应该使用拥有引用(owning reference):
- 当创建一个对象。
- 从任何获取函数中获得对象,例如QueryInterface和CreateInstance。
- 如果你将在函数的生命周期外保持引用。例如在类中做为一个指针成员保存。
在以下几种情况,不需要使用拥有引用(owning reference):
- 对象作为一个参数传入,并且不再函数生命周期外使用。
- 在一个良好的结构中,有一个对象A包含另一个对象B,B对象就不需要使用拥有引用。例如在树结构中,父对象
下是几个用例:
1.
不用nsCOMPtr
/*mFooPtr是一个原始的指针 nsIFooPtr * mFooPtr;*/
NS_IF_ADDREF(aFooPtr);
nsIFoo * temp = mFooPtr;
mFooPtr = aFooPtr;
NS_IF_RELEASE(temp);
如果使用nsCOMPtr:
/*nsCOMPtr<nsIFoo> mFooPtr;*/
mFooPtr = aFooPtr;
2. nsCOMPtr 比较简单明了
不使用nsCOMPtr
//原始的COM接口
nsIFoo *fooPtr = 0;
//……
fooPtr->SomeFunction(x, v, z);
AnotherFunction(fooPtr);
if (fooPtr)
//…..
if (fooPtr == foo2Ptr)
//….
使用nsCOMPtr
// |nsCOMPtr|..
nsCOMPtr<nsIFoo> fooPtr;
//...
fooPtr->SomeFunction(x, v, z);
AnotherFunction(fooPtr);
if (fooPtr)
//...
if (fooPtr == foo2Ptr)
//...
3. 不同:调用nsCOMPtr的 AddRef 和 Release 是不合法的,他们是私有的
不使用nsCOMPtr
/*注意:这不是正确设置指针的顺序,只是为了比较*/
// nsIFoo *mFOoPtr;
NS_IF_RELEASE(mFooPtr);
mFooPtr = aFooPtr;
NS_IF_ADDREF(mFooPtr);
使用nsCOMPtr
/*nsCOMPtr<nsFooPtr> mFooPtr;*/
NS_IF_RELEASE(mFooPtr); //ERROR |Release| 是私有的
mFooPtr = aFooPtr;
NS_IF_ADDREF(mFooPtr); //ERROR:|AddRef| 是私有的
4:不同: 当nsCOMPtr作为传出参数(out parameter), 需要使用apply_AddRefs
不使用nsCOMPtr
nsIFoo * foo;
GetFoo(&foo);
使用nsCOMPtr;
nsCOMPtr<nsIFoo> foo;
GetFoo(getter_AddRefs(foo));
5 获取接口
//不是最好的方法
nsCOMPtr<nsIFoo> foo;
nsresult rv = bar->QueryInterface(NS_GET_IID(nsIFoo), getter_AddRefs(foo));
//或者使用
nsresult rv = CallQueryInterface(bar, getter_AddRefs(foo));
// 比较好的方法
nsresult rv;
nsCOMPtr<nsIFoo> foo(do_QueryInterface(bar, &rv));
//或者
nsCOMPtr<nsIFoo> foo(do_QueryInterface(bar));
6 do_QueryInterface 防止XPCOM类型错误
在没有明确的允许, nsCOMPtr初始化不会隐工调用QueryInterface.除非初始化是用do_Queryface形式
class nsIBar
: public nsIFoo … {...};
nsIBar *p = …;
//C++ 认为第个nsIBar* 就是一个nsIFoo, 下面在C++中是被允许的
nsCOMPtr<nsIFoo> foo = p;
// 这是一个XPCOM类型错误
class nsIBar
: public nsIFoo … {...};
nsIBar *p = …;
//没有类型错误
nsCOMPtr<nsIFoo> foo(do_QueryInterface(p));
c++类型系统和XPCOM类型系统实际上是相互独立。由于[XP]COM接口的形式是抽象的C++基类,你可能会用C++处理不同类,或者使用C++的映射在不同的接口之间转换。这是错误的。唯一被认可的方法是通过QueryInterface在[XP]COM类型之间转换。在上面的例子中,通过C++ 获取的nsIFoo*值与QueryInterface()返回的值,不应该假设两个值是相同的。
7:dont_AndRef
如果指针已经调用过AddRefed,可又使用dont_AddRef赋值
nsCOMPtr<nsIFoo> foo(dont_AddRef(CreateFoo()));

浙公网安备 33010602011771号