Refptr and PassRefPtr basic(二)

2014-11-24 10:42:34 · 作者: · 浏览: 1
b = getOrdinaryNode();

// the * operator

*a = value;

// the -> operator

a->clear();

// null check in an if statement

if (a)

log(not empty);

// the ! operator

if (!a)

log(empty);

// the == and != operators, mixing with rawpointers

if (a == b)

log(equal);

if (a != b)

log(not equal);

// some type casts

RefPtr d =static_pointer_cast (a);

注:RefPtr对多种操作符都进行了重载

一般来说,RefPtr和PassRefPtr践行了一个简单的规则:他们总是平衡ref和deref调用,来保证程序员不会丢失对deref的调用。但是对于我们已经有了一个原始指针,并且有了引用计数,希望能够转移它的所有权的情况,应该使用adoptRef函数。

RefPtr node =adoptRef(rawNodePointer);

反过来,如果想把RefPtr传递给一个原始指针,而不改变引用计数,那么就要使用PassRefPtr的leakRef函数

RefPtr和new objects

在这里的例子中,我们谈论的对象都是引用计数为0,但是为了效率和简化,RefCounted类根本不使用引用计数0。对象在创建的时候就使用引用计数1.最好的编程实践是在new以后,马上把它们放进RefPtr,这样可以防止程序员在用完这些对象的时候忘记调用deref,让RefPtr帮助我们管理这些对象。也就是说,任何人调用new创建一个对象后,要马上调用adoptRef(该函数会返回一个PassRefPtr)。在WebCore中我们使用命名为create的static函数,而不是直接使用new

PassRefPtr Node::create()

{

return adoptRef(new Node);

}

RefPtr e = Node::create();

从adoptRef和PassRefPtr的实现,我们可以看到它们是很高效的。对象的起始引用计数是1,而且在创建过程中没有任何对引用计数的操作

// preferred style

PassRefPtr createSpecialNode()

{

RefPtr a = Node::create();

a->setCreated(true);

return a.release();

}

RefPtr b = createSpecialNode();

Node对象在Node::create中,被adoptRef放进PassRefPtr中,然后通过RefPtr的重载过的=操作符赋值给RefPtr对象a,最后在函数返回的时候,RefPtr的release函数返回PassRefPtr对象,然后又通过赋值操作赋值给RefPtr对象b,这期间没有对引用计数发生过任何操作。

RefCounted类实现了一个运行期的检查,如果我们再创建一个对象之后,没有调用adoptRef,而调用ref或者deref将会发生assertion。

使用指南

在WebKit代码中使用RefPtr和PassRefPtr应遵守如下的使用指南:

本地变量

如果所有权和生命期可以保证是在局部的,那么本地变量可以使用原始指针

如果代码需要保持住所有权或者保证生命期,那么应该使用RefPtr本地变量

永远不要使用PassRefPtr作为本地变量

成员变量

如果能够保障成员变量的所有权和生命期,成员变量可以使用原始指针

如果类需要获得所有权或者保证生命期,那么成员变量应该使用RefPtr

成员变量永远不要使用PassRefPtr

函数参数

如果函数不用于获取对象的所有权,那么参数可以使用原始指针

如果函数需要获取对象的所有权,那么参数应该是PassRefPtr。大部分的setter函数都应该如此设计。除非参数非常简单,否则的话,参数应该在函数一开始就传递给RefPtr对象,通常函数参数名称可以以”prp”作为前缀

函数结果

如果函数结果是一个对象,但是该对象的所有权还是属于原来对象,那么这个返回对象应该是一个原始指针,大部分的getter函数都是如此定义的(注:即结果对象是包含在原始对象中的,通过getter只是返回其引用或者指针,但是该返回的对象仍然从属于原始对象)

如果函数结果是一个新生成的对象或者它的所有权因为某种原因需要转移,那么这个结果应该使用PassRefPtr(该对象可以转移所有权)。因为本地变量一般使用RefPtr,所以在函数返回的时候,应该调用RefPtr的release函数返回一个PassRefPtr对象

新对象

新创建的对象在创建后需要马上放入到RefPtr中,这样只能指针就是自动控制引用计数操作

对于RefCounted对象,应该使用adoptRef函数把它放入到PassRefPtr中。

注:WebCore中的例子

static PassRefPtr DocumentLoader::create(constResourceRequest& request, const SubstituteData& data)

{

returnadoptRef(new DocumentLoader(request, data));

}

DocumentLoader继承自RefCounted

最好的创建方式是,使用私有的构造函数,和共有的创建函数,该创建函数返回一个PassRefPtr,(注:采用私有的构造函数,就防止外界使用new来创建新的对象,必须使用类提供的静态创建函数,该函数保证了对象在被创建后马上就被放入到RefPtr中)

这篇文章是关于Webkit中一系列非常基础的类的说明,看明白这篇文档之前还需要了解如下信息:

RefCounted是所有智能指针的基类,它提供了ref和deref操作,用于增减引用计数,RefCounted还有它自己的基类,RefCountedBase。

为了解决引用计数在作为参数和返回值的时候,频繁增减的问题,引入RefPtr和PassRefPtr对象,和一系列使用这些对象的规则

首先需要说明的是RefPtr和PassRefPtr是模板,使用这些模板定义的对象同样也一个对象而不是指针,在这些对象中封装了对引用计数的ref和deref操作。

其次来看一些重要的方法实现,对于我们理解上述文档很有好处,

RefPtr::release(),该函数返回一个PassRefPtr对象,用于传递原始指针的所有权

PassRefPtr RefPtr::release()

{

PassRefPtr tmp = adoptRef(m_ptr);m_ptr = 0; return tmp;

}

PassRefPtr ::leakRef(),该函数返回原始指针

template inline T*PassRefPtr ::leakRef() const

{

T* ptr = m_ptr;

m_ptr = 0;

return ptr;

}

adop