nsCOMPtr

        nsCOMPtr是一个帮助防止泄漏的工具。

        nsCOMPtr是一个智能指针,使用方法与C或者C++的普通指针一样,例如可以使用->或*。与原始的c++指针不同的是。nsCOMPtr帮助你管理着XPCOMAddRef, ReleaseQueryInterface

    COM的一条原则是任何创建或者返回接口的函数都应该是已调用AddRef函数。

    当最后一个指向接口的指针释放(调用Release),接口就将会删除自己(delete self)。如果有显示的调用接口的AddRef,而没有调用Release,则这个对象将引起内存泄漏(对象所占用的内存将不会被收回)。

   拥有引用(owning reference)是通过显示调用AddRef 和Release的引用。

如果两个对象运行结束时,但相互拥有对方,这将引起两个对象回收失败。所以须要一种额外的机制,以破坏这种拥有环(ownership cycle)。

在以下几种情况下,应该使用拥有引用(owning reference):

  1. 当创建一个对象。
  2. 从任何获取函数中获得对象,例如QueryInterface和CreateInstance。
  3. 如果你将在函数的生命周期外保持引用。例如在类中做为一个指针成员保存。

在以下几种情况,不需要使用拥有引用(owning reference):

  1. 对象作为一个参数传入,并且不再函数生命周期外使用。
  2. 在一个良好的结构中,有一个对象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()));

posted @ 2011-11-03 23:06  Mingxx  阅读(1026)  评论(0)    收藏  举报