zoukankan      html  css  js  c++  java
  • WebKit源代码里的RefPtr智能指针

    WebKit源代码里的RefPtr智能指针的一些心得。

    Overview

    WebKit的智能指针由类族 RefPtr 来实现,其核心由三个类组成:

    • RefCounted
    • RefPtr
    • PassRefPtr

    其中RefCounted提供了引用计数器(一个int型成员),而RefPtr和PassRefPtr则提供了自动管理引用计数器的功能。根据RefPtr and PassRefPtr Basics的说法,最初并没有RefPtr和PassRefPtr,这两个类是2005年才加入的,在它们出现之前完全是靠找死的人工管理RefCounted的引用计数。RefCounted类本身是没有问题的,但它的使用方法相当繁琐,繁琐到开发人员发现很多内存泄露都是由于对方法ref()和deref()的调用不当而造成一半以上内存泄露的程度。为了简化RefCounted的使用方法,RefPtr诞生了,而为了更高效地传递参数,开发人员又创造了PassRefPtr。

    RefCounted

    RefCounted的源代码在这里:RefCounted.h

    这个文件里定义了两个类:非模板类RefCountedBase和模板类RefCounted,从名字上就能看出来RefCounted继承于RefCountedBase。像维护引用计数器这么简单的活儿只使用一个类就绰绰有余了,这里之所以做成两个类是为了减少template hoisting(实例化模板导致的代码膨胀)。总而言之,最终的RefCounted完成了这样的功能:

    • 定义了成员变量:int m_refCount
    • 定义函数ref
      1
      2
      3
      4
      5
              //
      void ref()
      {
          ++m_refCount;
      }
    • 定义函数deref
      1
      2
      3
      4
      5
      6
              //
      void deref()
      {
          if (derefBase())
              delete static_cast<T*>(this);
      }
      derefBase的定义是:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
              //
      // Returns whether the pointer should be freed or not.
      bool derefBase()
      {
          if (m_refCount == 1) {
            return true;
          }
       
          --m_refCount;
          return false;
      }

    上面的ref()和deref()就是RefCounted的核心功能了,不过有一点要注意的是RefCounted的析构函数是protected的,这样就不能直接定义RefCounted对象了,而是必须从RefCounted继承子类才能行。但是这里不同于一般的继承,这里玩了个小trick:

    1
    2
    3
    class Frame : public RefCounted<Frame> {
      // ...
    }

    和一般的继承不一样吧,之所以要写成这样的原因在于函数deref()能够删除正确的对象!在函数deref()里,如果计数器到了1,就必须把自己销毁(即delete this),但此时的RefCounted直接来一句delete this是不对的,因为如果有一个类Foo继承于RefCounted,那在RefCounted的成员函数里调用delete this只会触发RefCounted的析构函数,而不会触发Foo的析构函数。为了让RefCounted在delete this时能确定子类的类型,类Foo就得从RefCounted<Foo>继承,这样才能为在RefCounted中delete this提供便利:

    1
    delete static_cast<T*>(this);

    在编译时T的类型会被确定为Foo,因此上面这句代码会触发Foo的析构函数,另外由于Foo继承于RefCounted,RefCounted的析构函数随后会调用(虽然啥也没干)。

  • 相关阅读:
    安装cloudbase-init和qga批处理
    Windows添加自定义服务、批处理文件开机自启动方法
    Windows批处理:自动部署常用软件(静默安装)
    windows auto activate
    XML转译字符
    Leetcode908.Smallest Range I最小差值1
    Leetcode917.Reverse Only Letters仅仅反转字母
    Leetcode896.Monotonic Array单调数列
    Leetcode905.Sort Array By Parity按奇偶排序数组
    Leetcode892.Surface Area of 3D Shapes三维形体的表面积
  • 原文地址:https://www.cnblogs.com/dsky/p/2673170.html
Copyright © 2011-2022 走看看