今天继续阅读Firefox源码。 正式进入XPCOM的领域。这个领域水深得很啊。
泪奔了。咱COM本质论还没看呢。就要霸王硬上弓了。
好吧,不扯远了。也还好,弄懂了一些基本的概念,比如知道XPCOM是基于组件,也可以说是基于契约的编程。
所以在COM里面,接口是很重要的,Firefox的源码中 就我看的那个模块中,就有几个接口,像nsISupport,nsICache,之前一直没找到,原来在public下面,全部是idl文件类型,这个是COBRA中的规范,叫接口描述语言。有兴趣百度之吧。
我比较关注XPCOM的基接口:nsISupport,用它来干啥呢?
组件与基于接口的编程的两个最基本的问题是: 一个是组件生存期, 也称为对象所属关系; 另一个是接口查询, 它是在运行时刻确定组件能够提供哪些接口.
而这个基接口就是用来解决这两个问题的,他有三个基本方法:
Normal 0 7.8 磅 0 2 false false false MicrosoftInternetExplorer4 /* Style Definitions */ table.MsoNormalTable {mso-style-name:普通表格; mso-tstyle-rowband-size:0; mso-tstyle-colband-size:0; mso-style-noshow:yes; mso-style-parent:""; mso-padding-alt:0cm 5.4pt 0cm 5.4pt; mso-para-margin:0cm; mso-para-margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:10.0pt; font-family:"Times New Roman"; mso-ansi-language:#0400; mso-fareast-language:#0400; mso-bidi-language:#0400;}
AddRef, Release, 和 QueryInterface.
其中添加和删除引用可以解决对象所属关系的问题,查询接口负责第二个问题。
解决对象所属关系,是通过维护一个引用计数来完成的,这个其实不算陌生,因为在操作系统中有类似的概念,比较好理解。感觉XPCOM就是用了大量的单实例类(组件),然后利用指针对这些组件进行引用。
这使我想反过头看看NsCOMPtr这个智能指针到底是怎么回事了。看了网页资料后,感觉就是一个能够自动完成对接口引用进行维护的指针,即对组件有一个引用,则引用计数加一,销毁一个引用,则计数减一,为0则销毁组件对象。通过这样的方法,使得对组件的引用更加方便,并且无须担心由于忘记销毁对象引起的内存泄漏。
但是看完https://developer.mozilla.org/en/Using_nsCOMPtr/Getting_Started_Guide 后感觉还是有些不是很踏实,于是忙里偷闲看了下C++Primer,这本书简直是我的大爱啊。可是一直没有抽出时间读。shit. 上次看了12章,写了一篇日志,感觉又忘得七七八八了。sigh~
这次看的是13章,复制控制。
提出问题,解决问题的思路吧。
问题是这样的:两个对象A,B,对象中都有一个对C的引用(造成这种情况最常见的例子就是复制,java里面叫克隆,浅克隆就会出现这样的情况,因为只是简单的复制指向C的指针到新的类中),如果删除A,B其中一个,就把C也删除了。但是A B中剩下的那一个对象不知道C已经被删除了,谁叫他跟别人共享一个成员呢。于是就发生了内存泄漏:A->C->data !!!
解决这个问题的方法有两个:智能指针 和 定义值型类 (其实就是深克隆啦,就是复制的时候把对象全部都复制一遍)
这里只说智能指针的方法。
方法不难,思路都是维护一个引用计数,每次增加和删除都对技术进行加一减一,为0则清对象。问题来了,这个引用计数的变量放在那里呢?
唯一的方法就是独立一个类Ptr,让大家都引用他,而Prt中有两个成员,一个是引用计数,一个是指向被引用对象的指针:
也就是说A对象要引用Obj,不是直接引用,而是A引用Ptr,而Ptr引用Obj,所以调用的时候是A->Ptr->Obj。而复制A到B的时候,B中包括的是指向Obj的指针Ptr。但是我们还要做一件事情,就是实现一个复制构造函数,形如:
A (const A &obj)
一个复制构造函数就是:形参为类本身,一般是const标识,然后引用被复制对象。复制构造函数的相关知识,会在下一篇文章中说明。 boy, i need time, i need time !!!!!
这个复制函数怎么实现呢?其实很简单,除了对被复制对象中的所有成员变量进行复制外,还有就是Ptr(智能指针类)中的引用计数加一。
而同样的,我们还需要重写A的一个析构函数,在里面的代码是,智能指针对象的引用计数减一,然后判0,0则销毁智能指针对象,注意到销毁智能指针对象,将会连锁销毁被引用对象Obj。因为销毁智能指针将激发Ptr对象的析构函数,从而销毁Obj。
还有稍微复杂一点的赋值操作,这个也需要覆写,因为类中有智能指针,需要对其进行维护。赋值函数的思路就是首先对右操作数中对象的使用计数加1,然后对左操作数中对象的使用计数减1(0则开始销毁)