用 C 实现一个变长数组
我想用 C++ 的人都用过 std::vector 。它是一个可变长的数组,在很多时候都比 C 固有的定长数组要灵活。
C 里没有这样的标准化设施,但是写软件的人通常都会实现一个。正所谓,不厌其烦的重造轮子 :D 。这里我们不讨论造轮子的好坏问题,直接讨论下实现这么个东西的一点小技巧吧。总是固执于用谁做的轮子的问题,眼光就太短浅了。
一般的 vector 的实现,需要记录三个数据:数据空间的地址,空间大小,数组里已存在的元素个数。也可能是这三个元素的变体。比如在 msvc 的 stl 实现中,vector 保存的是三个 iterator:数组头指针、最后一个元素的指针、分配出来的全部空间的末尾指针。
msvc 的 vector 的分配策略是这样的。一开始不于分配空间,当第一个元素被 push back 后,空间扩展。通常,扩展的请求至少要满足请求扩展的尺寸,或者是讲已有的空间容量翻倍。比如,当你已经有 16 个单元的数组空间时,如果再申请 3 个,vector 会自己扩展到 32 个单元;若你一次要求从 16 个单元扩展到 40 个单元(超过 16*2),那么就直接扩展到 40 。
记得 stlport 也是类似的策略吧,实现的可能稍有不同。
正是如此,我们在用 vector 的时候要比较小心。如有可能,最好先 reserve 出需要的空间,而不是一个个的 push back 。否则,如果你从 0 个元素,push back 100 次,其空间会重新分配 8 次(1、2、4、8、16、32、64、128)。btw, 如果你经常这样做,最好实现一个优秀的 allocator 。IMHO ,msvc 的 stl 实现并不比 stlport 差,大多数性能差别都是因为 msvc 的 stl 实现未能给出一个通用的,优化过的分配器而已。(实现一个好的内存分配器,对于大的 C++ 软件项目,都值得去做)
今天想说的并不是怎么优化这个策略。是我这几天在写代码时发现,如果你遵照空间加倍这个策略来运作,其实并不需要三个变量来维持 vector 结构,两个就够了。那个表识容量大小的变量是多余的。:D
下面是段示范代码:
利用二进制逻辑运算的性质,我们只需要把新的尺寸和老的尺寸异或,再和老的尺寸比较,就可以知道,新的尺寸的二进制最高是 1 的那一位的位置是否大于老的尺寸。然后分配新尺寸的两倍,空间是绰绰有余的。
当然,如果你希望空间分配的恰到好处(2^n -1 ),可以稍微写的繁琐一点,以下代码在 32bit 机器上,可以把一个数字从它的二进制为 1 的最高位到最低位都填成 1 。
今天把前两天写的 gc 模块开源了,本来想放到 sourceforge 上,但是我懒的注册帐号。google code 看起来更方便,选了个 bsd 的许可。然后把代码上传了。
project 在这里 http://code.google.com/p/manualgc/ 暂无下载,请直接用 svn check out 。
开源要有勇气,尤其是这么 dirty 的代码。不过话说回来,程序写了这么多年,写代码早就不拘小节了。我感觉这个东西设计上有点意思,现在也没看到有人做类似的玩意,具体实现则是次要的东西。应该还是会对某些同学有点意义的。
暂时还没完整测试过,姑且用之,不喜欢的人请直接无视。
Comments
Posted by: GlacJAY | (14) June 29, 2009 02:18 PM
Posted by: highshow | (13) January 10, 2009 01:50 AM
Posted by: mike | (12) July 3, 2008 08:29 AM
Posted by: Cloud | (11) June 12, 2008 10:41 PM
Posted by: ajivact | (10) June 12, 2008 04:41 PM
Posted by: ajivact | (9) June 12, 2008 04:39 PM
Posted by: 天黑请闭眼 | (8) June 12, 2008 02:25 PM
Posted by: Cloud | (7) June 11, 2008 09:47 PM
Posted by: Zwinger | (6) June 11, 2008 08:17 PM
Posted by: 白鸟 | (5) June 11, 2008 01:15 PM
Posted by: dikatour | (4) June 11, 2008 01:07 PM
Posted by: Anonymous | (3) June 11, 2008 10:22 AM
Posted by: DD | (2) June 11, 2008 12:00 AM
Posted by: 我大心 | (1) June 10, 2008 10:38 PM