DataRef源码分析

如果转载本文,请注明出处!

DataRef是一个类模板,实现位于Source/WebCore/rendering/style/DataRef.h文件。
这个模板的内容真的是太少了,具体如下:
  • 成员变量m_data,类型为RefPtr
  • get方法,获取T*类型变量,与m_data.get()的功能完全相同。
  • 重载指针运算符"*"和"->"。
  • access方法,返回类型T*。
  • init方法,功能是初始化m_data。这个方法对泛型参数施加了一个约束:T必须实现create静态方法,且create方法返回PassRefPtr类型参数。
  • 重载比较运算符"=="和"!="。

初次看到这个模板的实现时,我不仅疑惑:直接使用RefPtr不行吗?为什么一定要用一个DataRef来封装RefPtr呢?这不是脱裤子放屁,多次一举吗?思考之后,才发现这个类是有作用的!

简单来说,这个模板实现的功能是: 写时复制
各位看客应该记得“写时复制”的概念吧。我帮大家回忆一下。假设一个场景为:进程P打开一个文件,且将文件句柄设置为全局,然后P进程fork了一个子进程P-child。P-child刚创建时,共享了父进程P的全局变量。如果P-child需要对文件句柄设置新值,那么P-child就会把文件句柄拷贝一份,不再共享父进程的文件句柄了,之后再修改文件句柄,修改的是自己的拷贝,绝对不会影响父进程的文件句柄。这就是写时复制。
WebCore在修改DataRef对象时,一定是通过DataRef.access方法获得m_data的。DataRef.access方法的实现如下。

T* access()
{
    if (!m_data->hasOneRef())
        m_data = m_data->copy();
    return m_data.get();
}

看到加红加粗的两行了吗?秘密就在于此!如果m_data有多于1个引用,那么创建一个m_data的拷贝。之后操作m_data的拷贝。

 

再查一下DataRef的应用场景,就会明白webcore的苦心了。DataRef应用在RenderStyle类中。在写网页的时候,你会为各个节点都定义特殊样式吗?反正我不会,我认为几乎所有人都不会。也就是说,网页中大多数相同节点具有相同的样式。可以将这段话用代码表示如下。

pNode->renderStyle() == anotherPNode->renderStyle()

 

引入"写时复制"这个概念,就可以简化共享的实现复杂度。

你可能感兴趣的:(webkit,编程技巧)